为什么铁锈需要明确的生命周期?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (15)

struct Foo<'a> {
    x: &'a i32,
}

fn main() {
    let x;                    // -+ x goes into scope
                              //  |
    {                         //  |
        let y = &5;           // ---+ y goes into scope
        let f = Foo { x: y }; // ---+ f goes into scope
        x = &f.x;             //  | | error here
    }                         // ---+ f and y go out of scope
                              //  |
    println!("{}", x);        //  |
}                             // -+ x goes out of scope

在我看来,编译器防止的错误是免费使用的引用x*内部范围完成后,f因此&f.x变得无效,不应该分配给x

我的问题是这个问题可以很容易地被分析掉。使用显式'a生命周期,例如通过推断非法指定引用范围更广(x = &f.x;).

那么,在哪种情况下,需要明确的生命周期来防止使用后使用(或其他类?)错误?

提问于
用户回答回答于

这实际上与“编译器可以推断出为什么需要显式类型”的问题是一样的。一个假设的例子:

fn foo() -> _ {  
    ""
}

当然,编译器可以看到我正在返回一个&'static str,那么为什么程序员必须键入它呢?

主要原因是,虽然编译器可以看到代码所做的事情,但它不知道您的意图是什么。

函数是防火墙的自然边界,影响代码的变化。如果我们允许从代码中完全检查生命周期,那么一个看似无辜的更改可能会影响生命周期,这可能会在一个很远的函数中造成错误。这不是一个假设的例子。据我所知,当您依赖于顶级函数的类型推断时,Haskell就会遇到这个问题。铁锈把那个特殊的问题扼杀在萌芽状态。

为了验证类型和生存期,只需要解析编译器的函数签名也有效率的好处。更重要的是,它对程序员有效率的好处。如果我们没有显式的生命周期,这个函数会做什么:

fn foo(a: &u8, b: &u8) -> &u8

如果不检查源代码是不可能判断的,这将违背大量的编码最佳实践。

通过推断非法转让对更大范围的引用

范围基本上是生命周期。更清楚一点,一辈子'a通用寿命参数可以根据调用站点在编译时专门处理特定范围。

是否需要明确的生命周期来防止...错误?

一点也不。寿命需要防止错误,但需要明确的生命周期来保护小的正常程序员。

用户回答回答于

例如:

fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
    x
}

fn main() {
    let x = 12;
    let z: &u32 = {
        let y = 42;
        foo(&x, &y)
    };
}

在这里,明确的生命周期是重要的。这是因为foo具有与其第一个参数相同的生存期('a),所以它可能比第二个论点更有生命力。的签名中的生存期名称表示。foo,如果将调用中的参数切换到foo编译器会抱怨y活得还不够长。

扫码关注云+社区