简体   繁体   中英

Trait implements Iterator, but cannot use a struct implementing my trait as an Iterator

I have a trait and I want to say that if a struct implements this trait then it can also act as an Iterator . However I'm getting a compiler error when trying to use a struct as an iterator.

I am writing a library to read the same type of data from many different file formats. I want to create a generic "reader" trait, which will return the proper rust objects. I want to say that each reader can operate as an Iterator, yielding that object.

Here's the code

/// A generic trait for reading u32s
trait MyReader {
    fn get_next(&mut self) -> Option<u32>;
}

/// Which means we should be able to iterate over the reader, yielding u32s
impl Iterator for MyReader {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        self.get_next()
    }
}

/// Example of a 'reader'
struct MyVec {
    buffer: Vec<u32>,
}

/// This can act as a reader
impl MyReader for MyVec {
    fn get_next(&mut self) -> Option<u32> {
        self.buffer.pop()
    }
}

fn main() {
    // Create a reader
    let mut veccy = MyVec { buffer: vec![1, 2, 3, 4, 5] };

    // Doesn't work :(
    let res = veccy.next();
}

The compiler output:

rustc 1.15.0 (10893a9a3 2017-01-19)
error: no method named `next` found for type `MyVec` in the current scope
  --> <anon>:31:21
   |
31 |     let res = veccy.next();
   |                     ^^^^
   |
   = help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item `next`, perhaps you need to implement one of them:
   = help: candidate #1: `std::iter::Iterator`
   = help: candidate #2: `std::iter::ZipImpl`
   = help: candidate #3: `std::str::pattern::Searcher`

Here is the code on the rust playground.

In my mind, since MyVec implements MyReader , then it should be usable as an iterator, and hence I should be able to call .next() on it. Since I have implemented MyReader , then I should get an implementation for Iterator for free, right? The line impl Iterator for ... shows that Iterator is in scope, so I can't understand where the error comes from.

This line doesn't do what you think it does.

impl Iterator for MyReader {

This implements Iterator for the trait object MyReader . What you want is to implement Iterator for every type which also implements MyReader . Unfortunately, this is not possible due to the coherence rules.

In Rust, you can only implement a trait in either the crate that defines the trait, or the crate that defines the type you are implementing it on. (Things are a bit more complicated for generic types, but that's the basic idea.) In this case, Iterator is a trait from the standard library, so there is no way for you to implement it on arbitrary types that you didn't define. If you think about it, this makes sense, because otherwise you'd get ambiguity if one of those types has a pre-existing implementation of Iterator - which one would be used?

One solution is to wrap the type implementing MyReader in a newtype, and implement Iterator on that. Since you defined the newtype yourself, you are free to implement Iterator on it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM