为什么 rust 忽略 &str 的生命周期检查?

Why rust ignore lifetime checks on &str?

fn main() {
    let strA = "a";
    let result;

    {
        let strB = "abc";
        result = longest(strA, strB); // Will return strB
    }

    println!("The longest string is {}", result); // result now point to strB!!
}

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

正如我从 the Rust book

得到的

'a will get the concrete lifetime that is equal to the smaller of the lifetimes of x and y

那么为什么 strB 现在在其范围之外可见?

生命周期 'a 指的是字符串缓冲区的生命周期 str 而不是对该缓冲区的引用。所以 &str strB 的生命周期在块内。但是,"abc" 是一个常量字符串。这意味着 str 缓冲区的存储有 'static 生命周期,这意味着它保证比任何其他生命周期都长。因此,即使在 strB 不再引用它之后,结果引用该缓冲区也是有效的。

那是因为所有字符串文字都有 'static 生命周期。 From the rust book:

One special lifetime we need to discuss is 'static, which means that this reference can live for the entire duration of the program. All string literals have the 'static lifetime, which we can annotate as follows:

let s: &'static str = "I have a static lifetime.";

The text of this string is stored directly in the program’s binary, which is always available. Therefore, the lifetime of all string literals is 'static

固定示例:

fn main() {
    let strA = "a".to_string();
    let result;

    {
        let strB = "abc".to_string();
        result = longest(&strA, &strB); // Will return strB
    }

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

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

现在按预期生成编译器错误:

error[E0597]: `strB` does not live long enough
  --> src/main.rs:7:33
   |
7  |         result = longest(&strA, &strB); // Will return strB
   |                                 ^^^^^ borrowed value does not live long enough
8  |     }
   |     - `strB` dropped here while still borrowed
9  | 
10 |     println!("The longest string is {}", result); // result now point to strB!!
   |                                          ------ borrow later used here

playground

Rust 并没有“忽略”您初始示例中字符串变量的生命周期。当您将变量设置为字符串文字时,该文字会被硬编码到可执行二进制文件中并获得 'static 生命周期,这意味着它在程序的整个持续时间内都有效。如果我们向您的初始示例添加显式类型注释,那么它为什么可以编译和工作应该会很清楚:

fn main() {
    let strA: &'static str = "a";
    let result;

    {
        let strB: &'static str = "abc";
        result = longest(&strA, &strB); // returns 'static str
    }

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

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

然而,当我们在字符串文字上调用 to_string() 时,我们创建了一个拥有并分配了堆的 String,它的生命周期是非静态的,并且作用域是它所在的任何块,因此进行更改该程序不再按预期编译。