1

The following code:

struct Abc<I>
    where I: Iterator<Item=u64> {

    my_iter: I,
}

impl<I> Abc<I>
    where I: Iterator<Item=u64> {

    fn func1(&mut self) {
        self.my_iter = vec![1,2,3,4,5].into_iter();
    }
}

fails to compile with the following error:

error[E0308]: mismatched types
  --> src/abc.rs:16:24
   |
12 | impl<I> Abc<I>
   |      - this type parameter
...
16 |         self.my_iter = vec![1,2,3,4,5].into_iter();
   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `I`, found struct `std::vec::IntoIter`
   |
   = note: expected type parameter `I`
                      found struct `std::vec::IntoIter<{integer}>`

Why it doesn't work and how to fix it?

Thanks!

  • Why you declare Iterator? In fact, u64 not implementing Iterator. Could you explain your idea? – Zeppi Sep 30 '21 at 06:25
  • @Zeppi `Item=u64` means the type of the element the iterator yields. The idea is very simple: a struct has a field of iterator type and at some point we want to assign that field with a concrete iterator. – Dmitry Rusakov Sep 30 '21 at 06:43
  • You should use an associated type instead of a generic parameter. – Jmb Sep 30 '21 at 06:50
  • Does this answer your question? [When is it appropriate to use an associated type versus a generic type?](https://stackoverflow.com/questions/32059370/when-is-it-appropriate-to-use-an-associated-type-versus-a-generic-type) – Jmb Sep 30 '21 at 06:51

2 Answers2

1

The problem is that in Abc<I> the user of Abc can choose any I as long as it implements Iterator<Item = u64>. But Abc::func1() assumes a very specific iterator. There are two ways to resolve it:

One is to make func1() only available if the iterator type is the one it can work with:

struct Abc<I> {
    my_iter: I,
}

impl Abc<std::vec::IntoIter<u64>> {
    fn func1(&mut self) {
        self.my_iter = vec![1,2,3,4,5].into_iter();
    }
}

The other is to give up on generics and use a trait object instead:

struct Abc {
    my_iter: Box<dyn Iterator<Item = u64>>,
}

impl Abc {
    fn func1(&mut self) {
        self.my_iter = Box::new(vec![1,2,3,4,5].into_iter());
    }
}
user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • Or to declare the struct as holding a `std::vec::IntoIter` in the first place if the OP doesn't need it to hold anything else. – Jmb Oct 01 '21 at 07:09
  • @Jmb That would work too. I didn't consider that option because I found it unlikely that only that single iterator was ever needed in a generic function. But on the other hand, given that the OP is obviously a beginner, perhaps the use of generics was totally unintentional and arrived to using trial-and-error, in which case preserving it is a non-goal. – user4815162342 Oct 01 '21 at 07:24
0

The message of the compiler is correct, there is a type mismatch. You are trying to assign the value of type std::vec::IntoIter<{integer}> to a field with type I. You can see why this does not work with this example:

let mut val = Abc<MyCustomIteratorType<Item=u64>> { my_iter: MyCustomIteratorType::new() };
val.func1();

Here the call to func1 will try to replace my_iter of type MyCustomIteratorType to IntoIter.

I'm not sure what you are trying to achieve, but one option to fix this issue is:

struct Abc<I>
    where I: Iterator<Item=u64> {

    my_iter: I,
}

impl Abc<std::vec::IntoIter<u64>>
    fn func1(&mut self) {
        self.my_iter = vec![1,2,3,4,5].into_iter();
    }
}

You can have different implementaions of func1 for different iterator types.

Maxim Gritsenko
  • 2,396
  • 11
  • 25