Lifetime for owned guard

Hello!
I have a situation similar to the following, where I want to provide a reference, instead of a guard (Ref<'a, ()> in this case), which can be cumbersome to work with.

use std::cell::{RefCell, Ref};

struct Foo<'a> {
    data: &'a RefCell<()>,
    guard: Option<Ref<'a, ()>>
}

impl<'a> Iterator for Foo<'a> {
    type Item = &'a ();
    fn next<'b>(&'b mut self) -> Option<&'a ()> {
        self.guard = self.data.try_borrow().ok();
        if let Some(x) = &self.guard {
            Some(&**x)
        } else {
            None
        }
    }
}

[Playground]
I currently get:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/lib.rs:12:26
   |
12 |         if let Some(x) = &self.guard {
   |                          ^^^^^^^^^^^
   |

This could be fixed by changing the definition of next:

fn next<'b>(&'b mut self) -> Option<&'a ()> where 'a: 'b;

But, unfortunately I can't redefine Iterator, as though it's pretty important. Is there any way to solve this lifetime issue?

Iterators won't do the job your after.
The return item from next is never bound to the life of the iterator (The variable storing the iterator not 'a) or borrow ('b)
Every time next is called self.guard gets replaced so you can't take a borrow from it that will last.

Your "fix" link shows 'b:'a swap it around and it fails. With 'b:'a you don't get to call next a second time until the first result is dropped.

Maybe something like for_each(cb: impl Fn(&()) ) would do.

Note the lifetime you add in structure is also off; ('static in unit type)

struct Foo<'a, 't, T:'t> {
    data: &'a RefCell<T>,
    guard: Option<Ref<'t, T>>
}

No direct link between 'a and 't. Variance allows 'a to be used.

When you deref guard the returned reference is restricted to that borrow (ie 'b)

Edit: Was reading Ref when came up with above, but is wrong (after trying small bit of code.) Ref lifetime parameter is set at/from call to try_borrow (or borrow)

1 Like

Like whar @jonh said, you can't use the Iterator interface for this, you can use the streaming iterator interface for this however, which can be found here.

https://crates.io/crates/streaming-iterator

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.