1

I am trying to create an iterator that wraps another iterator with a given associated type and does some additional work. I'm using generic types because it's not pretty to write out the concrete type of the wrapped iterator. I've reduced the error to the following code.

trait Trait {
    fn doit(&self);
}

struct S1 {}
impl Trait for S1 {
    fn doit(&self) {}
}

fn create_s1() -> S1 {
    S1 {}
}

fn create<S>() -> S
where
    S: Trait,
{
    create_s1()
}

fn main() {
    let s = create::<S1>();
}

The error I get is:

error[E0308]: mismatched types
  --> src/main.rs:18:5
   |
14 | fn create<S>() -> S
   |                   - expected `S` because of return type
...
18 |     create_s1()
   |     ^^^^^^^^^^^ expected type parameter, found struct `S1`
   |
   = note: expected type `S`
              found type `S1`

It seems clear to me that create_s1() returns type S1 and that type S1 implements Trait. Why can't the compiler figure out the type of S?

I'm using rustc 1.32.0-nightly (b3af09205 2018-12-04)

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
knutaf
  • 11
  • 1
  • 1
    You are attempting to lie to the compiler. `create()` means that the caller of `create` can pick whatever concrete type for `S` that they'd like, but your function is only capable of returning a specific concrete type. – Shepmaster Dec 06 '18 at 01:10
  • Thank you, your explanation makes sense to me. I tried searching for this but somehow didn't find any of the things you linked. I was "abusing" generics to avoid writing an ugly-looking type (like `std::iter::Cycle>`). Are there shortcuts to avoid having to actually type that out? I haven't found any so far. – knutaf Dec 06 '18 at 03:45
  • That's what the latter two duplicates are pointing you to, especially [What is the correct way to return an Iterator (or any other trait)](https://stackoverflow.com/questions/27535289/what-is-the-correct-way-to-return-an-iterator-or-any-other-trait). TL;DR: `-> impl Iterator` (or whatever). – Shepmaster Dec 06 '18 at 04:05
  • You're right. I over-reduced my question. Rather than return it from a function, if I want to store it in a struct, I found that `Box + 'v>` works, but impl Trait isn't allowed in that position, and I don't know if some other syntax exists to solve it. – knutaf Dec 06 '18 at 06:09
  • You can always make your struct generic like `S<'v, T: Iterator + 'v>`, or if you don't want to use a generic and need to use the type in several places, you can shorten it with a type alias: `type MyType = std::iter::Cycle>;` and then simply use `MyType` everywhere. – Jmb Dec 06 '18 at 07:25

0 Answers0