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

278

我正在阅读 Rust 书籍的 生命周期章节 , 我看到了一个命名/显式生命周期的例子:

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;”)。在哪些情况下需要显式生命周期才能防止使用后释放(或其他类)错误?

1
这篇文章已经cross posted to Reddit - Shepmaster
4
对于未来阅读此问题的读者,请注意它链接到该书的第一版,现在已经有了第二版 :) - carols10cents
11个回答

0
这归结于编译器的性能。
Rust编译器只关注函数的签名,而不是其具体实现。这就是为什么我们明确声明输入生命周期和输出生命周期之间的关系。
fn longest_string<'a>(x: &'a str, y: &str) -> &'a str {
    x
}

fn main() {
    let string1 = "abcdef";
    let string2 = "xyz";
    let result;

    result = longest_string(&string1, &string2);

    println!("The longest string is {}", result);
    println!("The longest string is {}", result);
}

详细信息:在longest_string函数中,我们从函数中返回一个引用,并且该引用指向一些数据(即x内的数据)。尽管在longest_string的实现中我们总是返回x,但Rust编译器只关注函数签名,而不是函数体,以确定对引用的生命周期做出了哪些保证。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接