Confusion about lifetimes


#1

I am trying to learn more about Rust be reimplementing a toy version of some other code I have written:

http://is.gd/MWMhfA

I get this error:

54:38 error: cannot infer an appropriate lifetime due to conflicting requirements

around some code like:

pub struct Composed<F1, F2> { first: F1, second: Arc<F2> }
impl<X, F1, F2> FlatMapper<X> for Composed<F1, F2>
  where F1: FlatMapper<X>,
        F2: FlatMapper<<<F1 as FlatMapper<X>>::Output as Iterator>::Item> {

  type Output = Box<Iterator<Item = <<F2 as FlatMapper<<<F1 as FlatMapper<X>>::Output as Iterator>::Item>>::Output as Iterator>::Item>>;
  fn apply(&self, i: X) -> <Self as FlatMapper<X>>::Output {
    let it1 = self.first.apply(i);
    let sec = self.second.clone();
    box it1.flat_map(|y| sec.apply(y))
  }

}

I expected that sec would be dropped when the result of flat_map is dropped, and there would be no problem. But I guess that is not the case.

I’d love a clear explanation of why my expectation is incorrect and also any suggestions to change the design to have the same effect without hitting this issue.

Thanks in advance for any time spent helping me learn.


#2

First, the closure |y| sec.apply(y) captures sec by reference so you can’t return it from the function. Instead, you need to use move |y| sec.apply(y) which tells rust that you want to “move” the environment into the closure (capture by value).

However, that still doesn’t work because the Output type and F2 type might contain references so you also need to specify its lifetime (rust recommends the 'static lifetime.

Regardless, the diagnostic message could definitely be improved. This issue seems to be related: https://github.com/rust-lang/rust/issues/20253


#3

Thanks for the reply.

  1. why can’t the move be inferred in this case? Clearly sec will no longer be used after the call.
  2. how do put the 'static lifetimes in this case?

#4
  1. move is not inferred for closures.
  2. + 'static