我想使用一些最小的示例库代码:
struct MyR<'a> {
x: &'a str,
}
struct T {
x: &'static str,
}
impl T {
fn bar<'a>(&'a self) -> MyR {
MyR { x: self.x }
}
}
以下是我的代码:
trait A<R, F: FnMut(&R)> {
fn foo(&mut self, callback: &mut F);
}
impl<'a, F> A<MyR<'a>, F> for T
where F: FnMut(&MyR<'a>)
{
fn foo(&mut self, callback: &mut F) {
let t = T { x: "l" };
let r = t.bar(); // t does not live long enough (for 'a)
callback(&r);
println!("abc");
}
}
fn test() {
let mut t = T { x: "l" };
let mut i = 1;
t.foo(&mut |x| { i += x.x.len(); });
}
我想制作一个由回调参数化的特性,但我努力使其正确。如果我不使用特性,它运作良好:
impl T {
fn foo<F: FnMut(&MyR)>(&mut self, callback: &'a mut F) {
let t = T { x: "l" };
let r = t.bar();
callback(&r);
println!("abc");
}
}
但我不能这样做:
impl T {
fn foo<'a, F: FnMut(&MyR<'a>)>(&mut self, callback: &mut F) {
let t = T { x: "l" };
let r = t.bar();
callback(&r);
println!("abc");
}
}
我知道问题是t
必须比'a
更长,但我不知道绑定'a
以使其生命周期短于t
。
我每晚使用rustc 1.19.0。
答案 0 :(得分:1)
阅读错误消息:
t
活得不够长 - 它会一直存在到foo
函数的末尾。 借用的值必须在生命周期内有效 - 您指定'a
:
impl<'a, F> A<MyR<'a>, F> for T
where F: FnMut(&MyR<'a>)
这表示对于任何可能的生命周期,只要F
实现FnMut
特征,就会实施特征。
只有一种可能的方式才能实现这一目标 - 您必须拥有MyR
,其参数化为'static
生命周期。这是唯一一个保证比任意生命寿命更长寿命的生命。
让我们看看MyR
来自哪里:
fn bar<'a>(&'a self) -> MyR {
MyR { x: self.x }
}
如果您返回并重新阅读The Rust Programming Language section on lifetime elision,您就会发现此生命周期规范没有提供任何价值。它定义了一个生命周期并将其与self
一起使用,但它从未与任何输出生命周期相关联。代码与:
fn bar<'a, 'b>(&'a self) -> MyR<'b>
如果你删除了生命周期,那么你就
了fn bar(&self) -> MyR
fn bar<'a>(&'a self) -> MyR<'a> // equivalent
但是,这些都不是'static
生命周期。幸运的是,您知道x
是&'static str
,所以您可以在签名中反映出来,代码将编译:
fn bar(&self) -> MyR<'static>
答案 1 :(得分:0)
花费数小时尝试不同的方法,这似乎有效
trait A<F> {
fn foo(&mut self, callback: &mut F);
}
impl<F> A<F> for T
where F: FnMut(&MyR)
{
fn foo(&mut self, callback: &mut F) {
let t = T { x: "l" };
let r = t.bar(); // t does not live long enough (for 'a)
callback(&r);
println!("abc");
}
}
fn main() {
let mut t = T { x: "l" };
let mut i = 1;
t.foo(&mut |x: &MyR| { i += x.x.len(); });
}
主要区别在于: