Confused about lifetimes, pls help

Hi,

I've been struggling for a few days with a borrow checker problem and been unable to figure out what the Problem is. The actual code I'm working on is about computations on graphs, but for a minimalish example I've used some simple integer computations.

trait IteratorProducer<T> {
    fn iterator<'a>(&'a self) -> Box<dyn Iterator<Item = T> + 'a>;
    // Default implementation. Actual trait impls might have a more
    // efficient way to implement this.
    fn transformed<'a>(&'a self) -> Box<dyn Iterator<Item = T> + 'a> {
        Box::new(self
            .iterator()
            // Here rustc complains that i has insufficent lifetime. Why?
            .map(|i| self.transform(i)))
    }
    fn transform(&self, x: T) -> T;
}

struct RangeIterator {}

impl IteratorProducer<i32> for RangeIterator {
    fn iterator<'a>(&'a self) -> Box<dyn Iterator<Item = i32> + 'a> {
        Box::new(1..10)
    }
    fn transform(&self, x: i32) -> i32 {
        x + 1
    }
}

#[test]
fn test_it() {
    let ri = RangeIterator {};
    let bi: Box<dyn IteratorProducer<_>> = Box::new(ri);

    let values: Vec<_> = bi.iterator().collect();
    let larger_values: Vec<_> = bi.transformed().collect();
    dbg!(values);
    dbg!(larger_values);
}

rustc's opinion, with a tip that didn't work:

error[E0309]: the parameter type `T` may not live long enough
 --> tests/borrow.rs:6:9
  |
6 | /         Box::new(self
7 | |             .iterator()
8 | |             // Here rustc complains that i has insufficent lifetime. Why?
9 | |             .map(|i| self.transform(i)))
  | |________________________________________^ ...so that the type `T` will meet its required lifetime bounds
  |
help: consider adding an explicit lifetime bound...
  |
1 | trait IteratorProducer<T: 'a> {

Hints about what is going on here would be appreciated.

I think you need to add a where T: 'a clause to the iterator() and transformed() methods so the lifetime of theT being yielded isn't shorter than the &'a self reference.

trait IteratorProducer<T> {
    fn iterator<'a>(&'a self) -> Box<dyn Iterator<Item = T> + 'a>
    where
        T: 'a;

    // Default implementation. Actual trait impls might have a more
    // efficient way to implement this.
    fn transformed<'a>(&'a self) -> Box<dyn Iterator<Item = T> + 'a>
    where
        T: 'a,
    {
        Box::new(
            self.iterator()
                // Here rustc complains that i has insufficent lifetime. Why?
                .map(|i| self.transform(i)),
        )
    }

    fn transform(&self, x: T) -> T;
}

struct RangeIterator {}

impl IteratorProducer<i32> for RangeIterator {
    fn iterator<'a>(&'a self) -> Box<dyn Iterator<Item = i32> + 'a>
    where
        i32: 'a,
    {
        Box::new(1..10)
    }
    fn transform(&self, x: i32) -> i32 {
        x + 1
    }
}

#[test]
fn test_it() {
    let ri = RangeIterator {};
    let bi: Box<dyn IteratorProducer<_>> = Box::new(ri);

    let values: Vec<_> = bi.iterator().collect();
    let larger_values: Vec<_> = bi.transformed().collect();
    dbg!(values);
    dbg!(larger_values);
}

(playground)

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.