生命周期处理如何处理具有泛型类型的Fn特征对象?

时间:2019-01-16 18:37:34

标签: rust lifetime

以下代码按预期失败:

struct T<'a> {
    f: &'a Fn(&'a i32),
}

fn test<'a>(_: &'a i32) {}

fn main() {
    let t = T { f: &test };

    {
        let v = 4;
        (t.f)(&v);
    }

    let v1 = 5;
    (t.f)(&v1);
}

出现错误:

error[E0597]: `v` does not live long enough
  --> src/main.rs:12:15
   |
12 |         (t.f)(&v);
   |               ^^ borrowed value does not live long enough
13 |     }
   |     - `v` dropped here while still borrowed
...
16 |     (t.f)(&v1);
   |     ----- borrow later used here

原因是特征对象在其通用类型上是不变的。结果,在通话期间'a的{​​{1}}将不会缩短。我明白了但是,如果我删除以下代码段:

t.f()

代码可以很好地编译,我也明白这一点,因为我认为这是由于非词法生存期所致。

当我借用let v1 = 5; (t.f)(&v1); (或其中的某些字段)时,事情变得很有趣。考虑上面代码的稍微修改后的版本:

t

该代码可以编译,但是我不明白为什么!这里借用struct T<'a> { f: &'a Fn(&'a i32), i: i32, } fn test<'a>(_: &'a i32) {} fn main() { let t = T { f: &test, i: 1 }; let n = &t.i; { let v = 4; (t.f)(&v); } println!("{:?}", n); } ,结果借用t.i并在内部作用域结束后使用。我期望这会因上述编译器错误而失败。

作为对策,以下代码借用了整个t并无法使用与上面相同的消息进行编译。

t

1 个答案:

答案 0 :(得分:0)

实际上,它和其他方法一样工作。

struct T<'a> {
    f: &'a Fn(&'a i32),
}

此定义表示f函数将存在于'a中,并且它的参数也必须存在'a中。

fn main()的生存期视为'm,将内部范围的生存期视为'i。您正在main中创建结构,因此生命周期将是'm,除非您进入另一个范围,否则它将在main中生活。

  1. 在第一个示例中,您传递给t.f的参数是 在'i中创建。根据定义;论证与 函数必须存在相同的生命周期。但是'm大于'i。因此,这是不可接受的。
  2. 在您的第二个示例中,所有内容都相同,但您的结构实际上未超过'i。可以认为f的生存时间与其参数相等。因此,这确保了定义。
  3. 第三个示例与1相同。

如果您按如下所示更改定义,请从参数中删除约束。因此,编译器可以为参数推断适当的生存期,它的生存期可以更长,更长或更短。

//this means your f and it's argument's life time can be different
struct T<'a> {
    f: &'a Fn(&i32),
}

所有示例都是有效的。

在这里,您可以在Playground

中找到有效的示例