Rust 如何在不使用函数的情况下检测对局部变量的引用?

How does Rust detect a reference to a local variable without the function being used?

提问人:cadaniluk 提问时间:11/7/2023 最后编辑:cadaniluk 更新时间:11/7/2023 访问量:94

问:

假设一个函数返回一个对局部变量的悬空引用:

fn foo<'a>() -> &'a i32 {
    let i = 2;
    &i
}

fn main() { }

Rust 注意到了这一点并引发了一个错误。

添加生存期:

fn foo<'a>() -> &'a i32 {
    'b: {
        let i = 2;          // i has lifetime 'b
        &'c i
    }
}

Rust 推断,因为指的是 .此外,被实例化为 和 因此,因为返回类型是 ,返回值是 。我不明白为什么这里会发生错误,因为所有生命周期都可以用具体值实例化,而不会出现任何不匹配。'c = 'b&ii'a'c'b&'a i32&'c i32

如果是main

fn main() {
    'd: {
        let i_ref: &'d i32 = foo();    // foo() has lifetime 'b
    }
}

那么我们仍然会有 ,但是在 存在 lifetime 不匹配,因为不包含 。在这种情况下,我预计会出现错误。'a = 'c = 'bmain'b'd

在第一种情况下,Rust 如何在不调用的情况下检测悬空引用?foo

Rust 参考 生存期

评论

1赞 isaactfa 11/7/2023
你是在问为什么死代码会被借用检查,还是在问借用检查是如何在编译时而不是运行时发生的?
0赞 cadaniluk 11/7/2023
@isaactfa 实际上,我不会说。我知道借用检查是一个编译时过程,但我想知道为什么在这种特定情况下编译器如此聪明地注意到悬空引用,而不会在任何地方出现明确的生存期不匹配。
0赞 Masklinn 11/7/2023
不过,有终生不匹配吗? 是一个局部变量,因此其生存期在函数结束时结束,这与引用转义不兼容。该函数必须对每个 ,但它唯一可以工作的是 null 生存期。这不存在i'a
0赞 cadaniluk 11/7/2023
@Masklinn我认为这在......所以我想我的错误是认为 和 的寿命是一样的。但是 的生存期只从返回时的行开始(因此是 null 生存期),对吧?'aii&i&i
1赞 Sven Marnach 11/7/2023
所有泛型参数(包括类型参数、生存期参数和常量参数)始终由调用方提供。这直接意味着返回类型中出现的任何生存期都必须是 ,或者出现在函数参数类型之一中的生存期。'static

答:

1赞 Colonel Thirty Two 11/7/2023 #1

传递到非异步函数的所有生存期都必须对整个函数体有效 - 生存期不能在函数执行期间自发存在或失效。

此规则会自动排除返回本地引用,因为它们的生存期在函数返回之前有效地结束。

(异步函数略有不同 - 在后台,它们返回一个不透明的未来对象,该对象可能包含也可能不包含引用。但它们仍然阻止返回对堆栈分配变量的引用。


换一种思考方式:

foo<'a>() -> &'a i32让调用方选择它想要的任何生存期,只要(不存在的)参数的生存期与返回值匹配即可。我可以想象调用 ,根据函数签名的规则,它必须被接受,但显然对于返回局部变量的函数无效。foo::<'static>()

评论

0赞 cadaniluk 11/16/2023
关于你的最后一段:会引发错误,我同意,原因与我的问题(我已经编辑过)中的示例不起作用的原因相同。但是,只有通过调用 才能插入 。因此,我不明白为什么只给出函数的定义而没有调用,编译器有足够的信息来引发错误。的定义违反了关于生命周期的哪些具体规则?foo::<'static>()'static'afoofoo
0赞 Colonel Thirty Two 11/16/2023
@cadaniluk 我回答的第一部分中的规则,其中生存期必须在整个函数中有效。Rust 不像 C++ 那样,编译器等到模板实例化来检查泛型 - 它在定义函数时检查它们。
0赞 cadaniluk 11/16/2023
明白了。是的,这可能是我感到困惑的原因之一,我在模板和替换方面想得太多了。
0赞 cadaniluk 11/16/2023
但是,除了返回本地引用之外,输入生存期怎么可能不包含整个函数呢?这条规则在我看来是人为的,因为我看不出除了返回本地引用之外,它是如何防止更大类别的错误——它并不是真正的“基本”。
0赞 Colonel Thirty Two 11/16/2023
@cadaniluk 一般规则是引用不能逃避其引用的数据的范围