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