Here's an example that compiles fine:
use std::cell::RefCell;
use std::rc::Rc;
struct Foo<'a> {
val: Rc<RefCell<i32>>,
dummy: Option<&'a i32>,
}
fn consume<T>(_: T) {}
impl<'a> Foo<'a> {
// Note that &i32 has no lifetime markers
fn subscribe<F>(self, func: F)
where
F: Fn(&i32) + 'a,
{
let val = self.val.clone();
consume(move |x: i32| {
*val.borrow_mut() = x;
func(&*val.borrow())
})
}
}
Here's what what I'm trying to achieve and doesn't compile:
use std::cell::RefCell;
use std::rc::Rc;
trait Stream<'a> {
type Item: 'a;
fn subscribe<F>(self, func: F)
where
F: Fn(Self::Item) + 'a;
}
struct Bar<'a, S: Stream<'a>> {
stream: S,
val: Rc<RefCell<S::Item>>,
}
impl<'a, S: Stream<'a>> Stream<'a> for Bar<'a, S> {
type Item = &'a S::Item; // 'a doesn't seem right here...
fn subscribe<F>(self, func: F)
where
F: Fn(Self::Item) + 'a,
{
let val = self.val.clone();
self.stream.subscribe(move |x: S::Item| {
*val.borrow_mut() = x;
func(&*val.borrow());
})
}
}
This example is almost identical to the first. The only difference is that because it's a trait, we have to assign an explicit lifetime to the associated type, Item
, which is a reference. Setting it to 'a
causes lifetime conflicts (rightfully so):
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/lib.rs:27:24
|
27 | func(&*val.borrow());
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime as defined on the body at 25:31...
--> src/lib.rs:25:31
|
25 | self.stream.subscribe(move |x: S::Item| {
| ^^^^^^^^^^^^^^^^^
note: ...so that closure can access `val`
--> src/lib.rs:27:20
|
27 | func(&*val.borrow());
| ^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 17:6...
--> src/lib.rs:17:6
|
17 | impl<'a, S: Stream<'a>> Stream<'a> for Bar<'a, S> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:27:18
|
27 | func(&*val.borrow());
| ^^^^^^^^^^^^^^
In fact, the first example can be modified to fail with exactly the same error if you were to replace Fn(&i32)
with Fn(&'a i32)
in the function signature.
Is it possible to make the second example compile? Possibly via the use of some hacks or unsafe blocks, I'd be willing to accept anything really. Changing signatures or reshuffling the logic if that's required. What should the lifetime of the associated type Item
be?