生命周期参数的语义

Semantics of lifetime parameters

考虑以下来自 the Book 的示例:

fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("The longest string is {}", result);
}

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

据说(强调我的)

The function signature now tells Rust that for some lifetime 'a, the function takes two parameters, both of which are string slices that live at least as long as lifetime 'a. The function signature also tells Rust that the string slice returned from the function will live at least as long as lifetime 'a. In practice, it means that the lifetime of the reference returned by the longest function is the same as the smaller of the lifetimes of the references passed in. These constraints are what we want Rust to enforce.

加粗的句子不应该是 函数签名还告诉 Rust 从函数中 returned 的字符串切片将存在于 most只要寿命'a.?这样,我们就可以放心,只要 xy 都还活着,那么 return 值也会有效,因为后者引用了前者。

换句话说,如果 xy 和 return 值都存在 至少与生命周期 'a[=36= 一样长],那么编译器可以简单地让 'a 成为一个空范围(任何项目都可以比它长寿)来满足限制,使注释变得无用。这没有道理,对吧?

我们可以从您的示例代码中稍微修改一下范围来考虑这种情况

fn main() {
    let string1 = String::from("abcd");

    {
        let string2 = "xyz";
        let result = longest(string1.as_str(), string2);
        println!("The longest string is {}", result);
    }
}

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

在这里,我们认识到对于上面的函数调用 longest,生命周期 a 最终成为 string2 的生命周期,因为参数 xy 必须至少与 a 一样长,所以如果 astring1 的生命周期,那么 longest 的第二个参数就是 string2 不会和 string1 一样长,并且“两个参数必须至少和 a 一样长”的说法是错误的。

我们承认 a 的生命周期是 string2 的生命周期。我们知道由 longest 编辑的字符串切片 return 可以是 string1string2。由于我们在声明中限制 return 值也至少与生命周期 a 一样长,我们实际上是说 return 值至少与 [= 一样长13=], 两个生命周期中较短的字符串.

如果 longest returned string2,那么 returned 字符串切片的寿命与生命周期 a 一样长。但是,如果 longest returned string1,则 returned 字符串切片将与 string1 的生命周期一样长,即 比 lifetime astring2 的生命周期)长,所以我们说从函数 returned 的字符串切片至少与 a.

这里需要注意的一件重要事情是我们不知道哪个切片 longest 会去 return,所以我们只允许 returned 引用的生命周期是两个生命周期中较小的一个,因为在两个生命周期中较小的一个,两个字符串肯定还活着。

用正式语言表达,注释翻译为:

for all 'a, 'a≤'x and 'a≤'y implies 'a≤'r

'x'y'r 的生命周期分别为 xy 和 return 值。

这将 return 值的生命周期链接到参数的生命周期,因为要使该关系保持 对于所有 'a,那么您必须具有 'x≤'r'y≤'r.

编译器将使用该注释两次:

  1. 编译注解函数时,编译器不知道xy的实际生命周期,也不知道'a(因为'a 将在调用站点选择,就像所有通用参数一样)。但它知道当函数被调用时,调用者将使用一些生命周期 'a 匹配输入约束 'a≤'x'a≤'y 并且它检查函数的代码是否遵守输出约束'a≤'r.

  2. 调用带注释的函数时,编译器将向其约束求解器添加一个未知范围 'a,其中可以访问 return 值,以及约束'a≤'x'a≤'y 加上由于周围代码而需要的任何额外约束,特别是 xy 的来源以及 return 值的使用方式.如果编译器能够找到一些匹配所有约束的范围 'a,那么代码将使用该范围进行编译。否则编译会失败并出现“寿命不够长”错误。