Rust life time and old iterator pattern

I found that Rust broke the old code, and I decided to fix it. Unfortunately, it seems that references to life have changed quite a bit, and something strange is happening. The field Counter.datadoes not matter, it is simply used to show that there is some data that I use, and refers to general material.

Here is the code:

struct Counter <'c, T: 'c> {
    val: u32,
    data: &'c T
}

struct CounterIterator<'c, T:'c> {
    iter: &'c mut Counter<'c, T>,
    num: u32
}

impl<'r, T> Iterator<u32> for CounterIterator<'r, T> {
    fn next(&mut self) -> Option<u32> {
        if self.num  == 0 {
            None
        } else {
            self.num -= 1;
            self.iter.incr()
        }
    }
}

impl<'c, T> Counter <'c, T> {
    fn new(dataz: &'c T) -> Counter<'c, T> {
        Counter {
            val: 0u32,
            data: dataz
        }
    }

    fn incr(&mut self) -> Option<u32> {
        self.val += 1;
        println!("{}", self.val);
        Some(self.val)
    }

    fn iter(&'c mut self, num: u32) -> CounterIterator<'c, T> {
        CounterIterator {
            iter: self,
            num: num
        }
    }
}

fn main() {
    let val = 11u;
    let mut cnt = Counter::new(&val);
    for i in range(0,2u) {
        cnt.incr();
    }

    for i in cnt.iter(3) {

    }

    cnt.incr(); // <- commenting this out "fixes" the problem
    // Otherwise the error is 
    // note: previous borrow of `cnt` occurs here; the mutable borrow prevents 
    // subsequent moves, borrows, or modification of `cnt` until the borrow ends

}

What is the mistake here? How to do this, so that the Iterator’s idiom ends with borrowing by the time it leaves the loop, and is it defined at the end of the block? Also, what are the obvious times of life T:'c?

For the record, I am trying to use the Iterator API, similar str.chars()in use. If there is a more robust way to do this, please let me know.

+4
1

fn iter, &'c mut self self 'c Counter. , cnt.incr(), cnt, ... cnt ( &'c mut self ).

- data Counter , :

struct Counter <T> {
    val: u32,
    data: T
}

, CounterIterator, Counter Counter.

// we now have a shorter lifetime ('s) and a longer one ('l). This is 
// expressed to the compiler by the 'l:  bound that says "'l lives 
// at least as long as 's"
struct CounterIterator<'s, 'l: 's, T: 'l> {
    iter: & mut Counter<'l, T>,
    num: u32
}

impl<'c,  T> Counter <'c, T> {
// ...
    // now the &mut self can live as long as CounterIterator, not necessarily as
    // long as Counter. This allows it to be released as soon as the iteration
    // is over and CounterIterator goes out of scope
    fn iter<'a>(&'a mut self, num: u32) -> CounterIterator<'a,'c, T> {
        CounterIterator {
            iter: self,
            num: num
        }
    }
}

, - :

$ rustc -v
rustc 0.12.0-pre-nightly (2e3858179 2014-09-03 00:51:00 +0000)
+2
source

All Articles