[solved] Wrapping an iterator around a trait


#1

Here’s a reduction of the problem I’m encountering, hopefully it is small enough to follow!

Briefly, I currently have implemented manual iteration from a BufRead via a helper function and I’m now trying to convert it into using the Iterator trait, but I can’t make the types work out. See the inline comments with the error messages.

I am still a Rust beginner, but I had expected the &mut self.r one to work!

use std::io;
use std::io::BufRead;

fn readone<R: BufRead>(r: &mut R) -> i8 {
    // Imagine this function pulls an i8 out of a BufRead,
    // the actual impl is irrelevant for this demo.
    return 1
}

struct Iter<'a, R>
    where R: BufRead + 'a {
    r: &'a R,
}

impl<'a, R> Iterator for Iter<'a, R>
    where R: BufRead + 'a {
    type Item = io::Result<i8>;
    fn next(&mut self) -> Option<io::Result<i8>> {
        // let x = readone(self.r);
        // error: mismatched types:
        //  expected `&mut _`,
        //     found `&'a R`

        // let x = readone(&mut self.r);
        // the trait `std::io::BufRead` is not implemented for
        // the type `&'a R` [E0277]

        let x = 3;
        // TODO: actually implement iterator, not important here.
        Some(Ok(x))
    }
}

fn main() {
    println!("Hello, world!");
}

#2

self.r is an immutable reference to R. You can’t make re-borrow that reference as mutable, since that would violate safety guarantees (there could be another mutable reference somewhere else).

You’ll have to make the reference inside Iter mutable:

struct Iter<'a, R>
    where R: BufRead + 'a {
    r: &'a mut R,
}

#3

Thank you! I was mislead by the structs docs, which say that structs cannot have mutable fields. But upon reading your answer it is now obvious that this field is still immutable, it just holds a mutable borrow!


#4

That section might be worded a bit confusingly. All struct fields are mutable as long as you own the struct, or have a mutable reference to it.