【问题标题】:Why rust ignore lifetime checks on &str?为什么 rust 会忽略 &str 的生命周期检查?
【发布时间】:2020-11-27 15:46:01
【问题描述】:
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 将获得等于xy较小 的生命周期的具体生命周期

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

【问题讨论】:

标签: rust lifetime borrow-checker ownership borrowing


【解决方案1】:

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

我们需要讨论的一个特殊生命周期是 'static,这意味着该引用可以在程序的整个持续时间内存在。所有字符串字面量都有 'static 生命周期,我们可以注释如下:

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

此字符串的文本直接存储在程序的二进制文件中,始终可用。因此,所有字符串字面量的生命周期都是 'static

【讨论】:

    【解决方案2】:

    固定示例:

    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,其生命周期是非静态的,并且作用域为它所在的任何块,因此进行更改会使程序不再编译为预计。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2015-10-15
        • 2013-10-27
        • 2013-07-03
        • 2022-11-23
        • 2019-02-24
        • 1970-01-01
        • 2017-05-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多