This is probably a super basic aspect of Rust, but I'm struggling with seeing through the levels of reference checks to make this make sense.
Imagine my current program sums all of the binary-encoded integers in a file:
pub fn read_int(file: &mut File) -> io::Result<i64> {
let mut int_buffer = [0; 8];
file.read_exact(&mut int_buffer)?;
Ok(i64::from_be_bytes(int_buffer))
}
fn read_loop() -> io::Result<f64> {
let mut file = File::open("data.dat")?;
let mut found_end = false;
let mut dat_sum = 0;
let mut dat_count = 0;
while !found_end {
match read_int(&mut file) {
Ok(d) => {
dat_sum += d;
dat_count += 1;
},
Err(_) => found_end = true
};
}
Ok(dat_sum as f64 / dat_count as f64)
}
I'd like to abstract over this to instead use a specialized i64 iterator:
fn read_loop() -> io::Result<f64> {
let mut int_iter = IntIterator::open("data.dat")?;
let mut dat_sum = 0;
let mut dat_count = 0;
for d in iiter {
dat_sum += d;
dat_count += 1;
}
Ok(dat_sum as f64 / dat_count as f64)
}
I tried implementing this, but:
pub struct TickIterator<'r> {
file: &'r mut File,
found_end: bool
}
impl<'r> TickIterator<'r> {
pub fn new(fp: String) -> io::Result<TickIterator<'r>> {
let mut file = File::open(fp)?;
Ok(TickIterator {
file: &mut file,
found_end: false
})
}
}
impl<'a> Iterator for TickIterator<'a> {
type Item = i64;
fn next(&mut self) -> Option<Self::Item> {
if self.found_end {
None
} else {
match read_int(self.file) {
Err(_) => {
self.found_end = true;
None
},
Ok(d) => Some(d)
}
}
}
}
It looks like I have a lot of problems to work out; the first error seems to be that I can't return the reference to file inside the struct because it is owned by the function new itself.
Is this the right approach, or am I going about things wrong here?