首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么在Rust中需要显式生命周期?

为什么在Rust中需要显式生命周期?
EN

Stack Overflow用户
提问于 2015-07-24 19:15:06
回答 10查看 25.4K关注 0票数 239

我正在读“生锈的lifetimes chapter”这本书,我偶然发现了这个例子,关于一个命名的/显式的生命周期:

代码语言:javascript
复制
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;)的非法引用赋值,可以很容易地分析出问题。

在哪些情况下,确实需要显式的生命周期来防止在释放后使用(或其他类?)错误?

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2015-07-24 21:38:00

其他的答案都有显著的要点(fjh's concrete example where an explicit lifetime is needed),但是缺少一个关键的东西:当编译器会告诉您错误的时候,为什么需要显式的生命周期

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

代码语言:javascript
复制
fn foo() -> _ {  
    ""
}

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

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

函数是防火墙的自然边界,不受代码更改的影响。如果我们允许从代码中完全检查生命周期,那么一个看起来无害的更改可能会影响生命周期,这可能会导致遥远的函数中出现错误。这不是一个假设的例子。据我所知,当你依赖顶级函数的类型推断时,Haskell就有这个问题。铁锈把那个特殊的问题扼杀在萌芽状态。

编译器还有一个效率优势--只需要解析函数签名就可以验证类型和生存期。更重要的是,它对程序员有效率上的好处。如果我们没有明确的生命周期,这个函数能做什么:

代码语言:javascript
复制
fn foo(a: &u8, b: &u8) -> &u8

不检查源代码就无法判断,这与大量的编码最佳实践背道而驰。

通过推断对更大范围的引用的非法赋值进行

从本质上讲,作用域是生命周期。更清楚的是,生命周期'a是一个通用的生命周期参数,它可以在编译时根据调用位置在特定范围内进行专门化。

是实际需要的显式生命周期,以防止...错误?

不用谢。需要生命周期来防止错误,但需要显式的生命周期来保护不太健全的程序员所拥有的。

票数 241
EN

Stack Overflow用户

发布于 2015-07-24 19:52:19

让我们看一下下面的例子。

代码语言:javascript
复制
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的生存时间不够长:

代码语言:javascript
复制
error[E0597]: `y` does not live long enough
  --> src/main.rs:10:5
   |
9  |         foo(&y, &x)
   |              - borrow occurs here
10 |     };
   |     ^ `y` dropped here while still borrowed
11 | }
   | - borrowed value needs to live until here
票数 111
EN

Stack Overflow用户

发布于 2015-07-25 18:47:31

以下结构中的生存期注释:

代码语言:javascript
复制
struct Foo<'a> {
    x: &'a i32,
}

指定Foo实例的生存期不应超过它所包含的引用(x字段)。

您在“生锈”一书中遇到的示例并没有说明这一点,因为fy变量同时超出了范围。

一个更好的例子是:

代码语言:javascript
复制
fn main() {
    let f : Foo;
    {
        let n = 5;  // variable that is invalid outside this block
        let y = &n;
        f = Foo { x: y };
    };
    println!("{}", f.x);
}

现在,f确实比f.x所指向的变量存活得更久。

票数 23
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31609137

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档