Вот пример, который прекрасно компилируется:
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())
})
}
}
Вот то, чего я пытаюсь достичь и не компилирую:
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());
})
}
}
Этот пример почти идентиченпервый.Единственное отличие состоит в том, что, поскольку это признак, мы должны назначить явное время жизни для ассоциированного типа, Item
, который является ссылкой.Установка его на 'a
вызывает конфликты времени жизни (справедливо):
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());
| ^^^^^^^^^^^^^^
Фактически, первый пример может быть изменен так, чтобы он завершился с ошибкой с той же самой ошибкой, если вы заменили Fn(&i32)
на Fn(&'a i32)
в сигнатуре функции.
Можно ли скомпилировать второй пример?Возможно, с помощью некоторых хаков или небезопасных блоков, я был бы готов принять что-нибудь действительно.Изменение подписи или перестановка логики, если это требуется.Каким должен быть срок службы ассоциированного типа Item
?