如何解决这个“活不够久”?

时间:2017-05-19 00:15:52

标签: rust

我想使用一些最小的示例库代码:

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。

2 个答案:

答案 0 :(得分:1)

阅读错误消息:

  1. t活得不够长 - 它会一直存在到foo函数的末尾。
  2. 借用的值必须在生命周期内有效 - 指定'a

    impl<'a, F> A<MyR<'a>, F> for T
        where F: FnMut(&MyR<'a>)
    

    这表示对于任何可能的生命周期,只要F实现FnMut特征,就会实施特征。

  3. 只有一种可能的方式才能实现这一目标 - 您必须拥有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(); });

}

主要区别在于:

  • 我必须稍微松散特性,以便它采用任意类型。
  • 因此,当我提出时,我根本不必指定生命。
  • 我必须在调用函数时键入注释闭包。

Playground