ayu*_*har 3 reference lifetime rust borrow-checker
Rust 一章指出,注释不会篡改变量的生存期,但是这是真的吗?根据这本书,最长的函数接受两个字符串引用,然后返回更长的字符串。但是在错误情况下
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("long string is long");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
}
println!("The longest string is {}", result);
}
Run Code Online (Sandbox Code Playgroud)
它实际上会改变结果变量的生存期,不是吗?
我们已经告诉Rust,最长函数返回的引用的生存期与传入的引用的生存期较小者相同。
What the book is merely suggesting is that a lifetime parameter of a function cannot interfere with the affected value's lifetime. They cannot make a value live longer (or the opposite) than what is already prescribed by the program.
However, different function signatures can decide the lifetime of those references. Since references are covariant with respect to their lifetimes, you can turn a reference of a "wider" lifetime into a smaller one within that lifetime.
For example, given the definition
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str
Run Code Online (Sandbox Code Playgroud)
, the lifetimes of the two input references must match. However, we can write this:
let local = "I am local string.".to_string();
longest(&local, "I am &'static str!");
Run Code Online (Sandbox Code Playgroud)
The string literal, which has a 'static lifetime, is compatible with the lifetime 'a, in this case mainly constrained by the string local.
Likewise, in the example above, the lifetime 'a has to be constrained to the nested string string2, otherwise it could not be passed by reference to the function. This also means that the output reference is restrained by this lifetime, which is why the code fails to compile when attempting to use the output of longest outside the scope of string2:
error[E0597]: `string2` does not live long enough
--> src/main.rs:14:44
|
14 | result = longest(string1.as_str(), string2.as_str());
| ^^^^^^^ borrowed value does not live long enough
15 | }
| - `string2` dropped here while still borrowed
16 | println!("The longest string is {}", result);
| ------ borrow later used here
Run Code Online (Sandbox Code Playgroud)
See also this question for an extended explanation of lifetimes and their covariance/contravariance characteristics:
首先,了解生命周期和作用域之间的区别很重要。引用具有生命周期,这取决于它们引用的变量的范围。
变量作用域是词法的:
fn main() {
let string1 = String::from("long string is long"); // <-- scope of string1 begins here
let result;
{
let string2 = String::from("xyz"); // <-- scope of string2 begins here
result = longest(string1.as_str(), string2.as_str());
// <-- scope of string2 ends here
}
println!("The longest string is {}", result);
// <-- scope of string1 ends here
}
Run Code Online (Sandbox Code Playgroud)
当您创建对变量的新引用时,引用的生命周期仅与变量的作用域相关。其他引用具有不同的生命周期信息,具体取决于引用来自何处以及在该上下文中已知哪些信息。当您在类型上放置命名的生命周期注释时,类型检查器只是确保附加到任何引用的生命周期信息与注释兼容。
fn main() {
let string1 = String::from("long string is long");
let result;
{
let string2 = String::from("xyz");
// The lifetime of result cannot be longer than `'a`
result = longest(string1.as_str(), string2.as_str());
// But a reference to string2 also has lifetime `'a`, which means that
// the lifetime `'a` is only valid for the scope of string2
// <-- i.e. to here
}
// But then we try to use it here — oops!
println!("The longest string is {}", result);
}
Run Code Online (Sandbox Code Playgroud)
我们已经告诉 Rust,最长函数返回的引用的生命周期与传入的引用的生命周期中的较小者相同。
有点。我们确实将这些信息告诉了 Rust,但是,借用检查器仍然会检查它是否属实!如果不是已经真的,那么我们会得到一个错误。我们无法改变这些信息的真实性,我们只能告诉 Rust 我们想要的约束,它会告诉我们我们是否正确。
在您的示例中,您可以main通过更改生命周期注释来使函数有效longest:
fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
if x.len() > y.len() {
x
} else {
y // oops!
}
}
Run Code Online (Sandbox Code Playgroud)
但是现在你在里面 得到一个错误,longest因为它不再满足要求:它现在永远无法返回,y因为它的生命周期可能比'a. 事实上,正确实现此功能的唯一方法是:
xx&'static str——因为'static所有其他生命周期都长unsafe代码