On Feb 5, 2013, at 8:02 PM, Niko Matsakis wrote:

> This is indeed what I mean and yes it can go wrong.  Let me spell out what 
> happens with the Iterator example, it's a bit involved and took me some time 
> to fully appreciate. To begin, today you have the following annotations on 
> the `next()` method, effectively:
> 
>     impl<'b, T> Iterator<'b, T> { 
>         fn next<T>(&'b mut self) -> Option<&'b T> { /* same as before */ } 
>     } 
> 
> As you can see, both the lifetime of the `&mut self` pointer and the lifetime 
> of the contents are `'b`.  Now let's have an example of some code that 
> invokes `next()`.  This is the standard `find()` function for vectors, 
> expressed with an iterator.  It iterates down the list and returns the first 
> item that matches some predicate `pred`.  I have included all possible 
> annotations and made all borrows explicit.  Key lines are numbered in 
> comments.
> 
>     fn find(v: &'lt [T], pred: &fn(&'lt T) -> bool) -> Option<&'lt T> {
>         let iterator = Iterator(v);
>         loop {
>             let result: Option<&'lt T> =    /* [1] */
>                 (&'lt mut iterator).next(); /* [2] */
>             match result {
>                 None => { return None; }
>                 Some(r) => {
>                     if pred(r) {
>                         return Some(r); /* [3] */
>                     } else {
>                         return None;
>                     }
>                 }
>             }
>         }
>     }
> 
> The lifetime of the input vector is 'lt.  The signature promises to invoke 
> the predicate function with data in the vector (and hence with the same 
> lifetime) and to return an element of the vector (and hence with the same 
> lifetime).  The first important point is that, when we call `next()`, the 
> lifetime of the resulting pointer must also be 'lt (as indicated in the type 
> annotation [1]).  This is because we are going to be returning this result if 
> it matches the predicate ([3]).  Now, because the lifetime of the pointer to 
> the iterator and the lifetime of the iteratee are specified as the same ('b), 
> this means that the lifetime of the borrow must be the same [2].
> 
> So, as a result of the above rules, the iterator is borrowed mutably for the 
> full lifetime 'lt.  This makes the borrow checker unhappy because it is only 
> supposed to allow one mutable alias to iterator at a time, but the scope of 
> the first mutable borrow outlives the enclosing loop (in fact, it outlives 
> the entire `find()` function), and thus it seems to the borrow checker that 
> you are creating new mutable aliases while the old ones still exist.  Thus 
> you get errors.  These problems go away when you don't artificially conflate 
> the lifetime attached to the `&self` pointer with the lifetime of the stuff 
> it points at.

Nice example. Just to make things completely absolutely clear: IIUC, you're 
saying that changing the (&'b mut self) argument to the next function into, 
e.g., (&'c mut self) --that is, a "free" lifetime (and I forget whether a 
binding site is required for this)--makes the code run correctly?

John

_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to