简体   繁体   English

了解生命周期:借来的价值还不够活

[英]Understanding lifetimes: borrowed value does not live enough

fn main() {
    let long; 
    let str1="12345678".to_string();
    {
        let str2 = "123".to_string(); 
        long = longest(&str1, &str2);
    }
    println!("the longest string is: {}", long);
} 

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

gives

error[E0597]: `str2` does not live long enough
 --> src/main.rs:6:31
  |
6 |         long = longest(&str1, &str2);
  |                               ^^^^^ borrowed value does not live long enough
7 |     }
  |     - `str2` dropped here while still borrowed
8 |     println!("the longest string is: {}", long);
  |                                           ---- borrow later used here

My theory is that, since the funtion longest has only one lifetime parameter, the compiler is making both x and y to have the lifetime of str1 .我的理论是,由于longest的函数只有一个生命周期参数,编译器使xy都具有str1的生命周期。 So Rust is protecting me from calling longest and possibly receive back str2 which has lifetime less than str1 which is the chosen lifetime for 'a .所以 Rust 保护我免于调用longest并可能接收str2 ,它的寿命小于str1 ,这是'a选择的寿命。

Is my theory right?我的理论对吗?

Let's take a closer look at the signature for longest :让我们仔细看看longest的签名:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str

What this means is that for a given lifetime 'a , both arguments need to last at least for the length of that lifetime (or longer, which doesn't really matter since you can safely shorten any lifetime in this case without any particular difference) and the return value also lives as long as that lifetime , because the return value comes from one of the arguments and therefore "inherits" the lifetime.这意味着对于给定的生命周期'a两个 arguments 都需要至少持续该生命周期的长度(或更长,这并不重要,因为在这种情况下您可以安全地缩短任何生命周期而没有任何特别的区别)并且返回值也与该生命周期一样长,因为返回值来自 arguments 之一,因此“继承”了生命周期。

The sole reason for that is that at compile time, you can't really be sure whether x or y will be returned when compiling the function, so the compiler has to assume that either can be returned.这样做的唯一原因是,在编译时,您无法确定在编译 function 时是否会返回xy ,因此编译器必须假设可以返回其中任何一个。 Since you've bound both of them with the same lifetime ( x , y and the return value have to live at least for the duration of 'a ), the resulting lifetime of 'a is the smallest one.由于您已将它们都绑定到相同的生命周期( xy和返回值必须至少'a的持续时间内存在),因此生成的'a生命周期是最小的。 Now let's examine the usage of the function:现在我们来看看function的用法:

let long; 
let str1 = "12345678".to_string();
{
    let str2 = "123".to_string(); 
    long = longest(&str1, &str2);
}

You have two lifetimes here, the one outside the braces (the main() body lifetime) and the lifetime inside the braces (since everything between the braces is destroyed after the closing brace).这里有两个生命周期,一个在大括号之外( main()主体生命周期)和一个在大括号内的生命周期(因为大括号之间的所有内容都在右大括号之后被销毁)。 Because you're storing the strings as String by using .to_string() (owned strings) rather than &'static str (borrowed string literals stored in the program executable file), the string data gets destroyed as soon as it leaves the scope , which, in the case of str2 , is the brace scope.因为您使用.to_string() (拥有的String )而不是&'static str (存储在程序可执行文件中的借用字符串文字)将字符串存储为字符串,所以字符串数据一离开 scope 就会被销毁,其中,在str2的情况下,是大括号 scope。 The lifetime of str2 ends before the lifetime of str1 , therefore, the lifetime of the return value comes from str2 rather than str1 . str2的生命周期在str1的生命周期之前结束,因此,返回值的生命周期来自str2而不是str1

You then try to store the return value into long — a variable outside the inner brace scope, ie into a variable with a lifetime of the main() body rather than the scope .然后,您尝试将返回值存储到long中——内括号 scope 之外的变量,即存储到具有main()主体而不是 scope 生命周期的变量中 But since the lifetime of str2 restricts the lifetime of the return value for longest in this situation, the return value of longest doesn't live after the braced scope — the owned string you used to store str2 is dropped at the end of the braced scope, releasing resources required to store it, ie from a memory safety standpoint it no longer exists.但是由于str2的生命周期在这种情况下限制了返回值 for longest的生命周期,因此在大括号 scope 之后, longest的返回值不会存在- 您用于存储str2的拥有字符串在大括号 scope 的末尾被丢弃,释放存储它所需的资源,即从 memory 安全角度来看,它不再存在。

If you try this, however, everything works fine :但是,如果您尝试此操作,则一切正常

let long; 
let str1 = "12345678";
{
    let str2 = "123"; 
    long = longest(str1, str2);
}
println!("the longest string is: {}", long);

But why?但为什么? Remember what I said about how you stored the strings, more specifically, what I said about borrowed string literals which are stored in the executable file.记住我所说的关于如何存储字符串的内容,更具体地说,我所说的关于存储在可执行文件中的借用字符串文字。 These have a 'static lifetime, which means the entire duration of the program's runtime existence.它们具有'static生命周期”,这意味着程序运行时存在的整个持续时间。 This means that &'static to anything (not just str ) always lives long enough , since now you're referring to memory space inside the executable file (allocated at compile time) rather than a resource on the heap managed by String and dropped when the braced scope ends.这意味着&'static对任何东西(不仅仅是str的寿命都足够长,因为现在您指的是可执行文件内的 memory 空间(在编译时分配),而不是由String管理的堆上的资源并在支撑 scope 结束。 You're no longer dealing with a managed resource, you're dealing with a resource managed at compile time , and that pleases the borrow checker by eliminating possible issues with its duration of life, since it's always 'static .您不再处理托管资源,而是处理在编译时管理的资源,并且通过消除其生命周期可能存在的问题来取悦借用检查器,因为它始终是'static的”。

This code for the developer's perspective looks good and it should be because we are printing long in the outer scope so there should be no problem at all.从开发人员的角度来看,这段代码看起来不错,应该是因为我们在外部 scope 中打印了很长时间,所以应该没有问题。

But Rust's compiler does a strict check on borrowed values and it needs to be sure that every value lives long enough for the variables that depend on that value.但是 Rust 的编译器会对借用的值进行严格检查,并且它需要确保每个值的生存时间足够长,以供依赖于该值的变量使用。

Compiler sees that long depends on the value whose lifetime is shorter that it's own ie str , it gives an error.编译器认为long取决于其生命周期比它自己的值更短的值,即str ,它会给出错误。 Behind the scenes this is done by a borrow checker.在幕后,这是由借用检查器完成的。

You can see more details about borrow checker here您可以在此处查看有关借阅检查器的更多详细信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM