这是一个可以很好编译的示例:
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)
,可以将第一个示例修改为失败,并出现完全相同的错误。
是否可以使第二个示例编译?可能通过使用一些hack或不安全的块,我愿意真正接受任何东西。如果需要,可以更改签名或改组逻辑。关联类型Item
的生存期应该是什么?
答案 0 :(得分:0)
您可以通过指定F
必须能够处理更通用的生命周期来编译第一个示例:
impl<'a> Foo<'a> {
fn subscribe<F>(self, func: F)
where
for<'b> F: Fn(&'b i32) + 'a, // f can cope with any lifetime 'b
{
let val = self.val.clone();
consume(move |x| {
*val.borrow_mut() = x;
func(&*val.borrow())
})
}
}
据我所知,您的第二个示例至少还遇到另一个问题:您致电
self.stream.subscribe(move |x: S::Item| {
*val.borrow_mut() = x;
func(&*val.borrow());
})
但subscribe
接受接受借用的函数(即&S::Item
,而不是S::Item
)。如果您传递参考,我不确定是否/如何将其分配给val.borrow_mut
。您可能必须将其转换为拥有的价值。
正如您已经提到的,您也可以设置Item = S::Item
(不借用)。但是,这意味着您不能简单地将val.borrow()
传递给闭包内的func
,因为这会从借入的值中转移出来。同样,解决方案可能是以某种方式将其转换为拥有的价值。