Edd*_*ett 9 lifetime rust memory-safety borrow-checker
我一直试图了解Rust的借款和所有权模式.
假设我们有以下代码:
fn main() {
let a = String::from("short");
{
let b = String::from("a long long long string");
println!("{}", min(&a, &b));
}
}
fn min<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.len() < b.len() {
return a;
} else {
return b;
}
}
Run Code Online (Sandbox Code Playgroud)
min()
只返回对两个引用字符串中较短者的引用.main()
传递两个字符串引用,其引用在不同的范围内定义.我已经使用过,String::from()
因此引用没有静态生命周期.程序正确打印short
.以下是Rust Playground中的示例.
如果我们引用Rustonomicon(我欣赏它是一个正在进行的工作文档),我们被告知函数签名的含义如下:
fn as_str<'a>(data: &'a u32) -> &'a str
Run Code Online (Sandbox Code Playgroud)
意味着功能:
引用一个
u32
有生命周期的东西,并承诺它可以产生一个str
可以存活一段时间的引用.
现在让我们转向min()
我的例子中的签名:
fn min<'a>(a: &'a str, b: &'a str) -> &'a str
Run Code Online (Sandbox Code Playgroud)
这更受欢迎,因为:
a
有效(有效期更长).使用与上面引用的语句类似的措辞,函数签名min()
是什么意思?
该函数接受两个引用,并且承诺产生一个引用,str
只要对象a
和 b
?这种感觉在某种程度上是错误的,好像我们将引用返回到b
from min()
,然后很明显,引用对于a
in 的生命周期是无效的main()
.
该函数接受两个引用,并且承诺产生对一个str
可以存活的引用,只要两个引用中的较短者a
和 b
?可以工作,因为这两个对象,a
并b
留在内部范围内有效main()
.
还有别的吗?
总而言之,我不明白min()
在调用者的不同范围内定义它们的引用时,将两个输入引用的生命周期绑定到同一生命周期意味着什么.
It's (2): the returned reference lives as long as the shorter input lifetime.
However, from the perspective of the function, both input lifetimes are in fact the same (both being 'a
). So given that the variable a
from main()
clearly lives longer than b
, how does this work?
The trick is that the caller shortens the lifetime of one of the two references to match min()
s function signature. If you have a reference &'x T
, you can convert it to &'y T
iff 'x
outlives 'y
(also written: 'x: 'y
). This makes intuitive sense (we can shorten the lifetime of a reference without bad consequences). The compiler performs this conversion automatically. So imagine that the compiler turns your main()
into:
let a = String::from("short");
{
let b = String::from("a long long long string");
// NOTE: this syntax is not valid Rust!
let a_ref: &'a_in_main str = &a;
let b_ref: &'b_in_main str = &b;
println!("{}", min(&a as &'b_in_main str, &b));
// ^^^^^^^^^^^^^^^^^^
}
Run Code Online (Sandbox Code Playgroud)
This has to do with something called subtyping and you can read more about this in this excellent answer.
To summarize: the caller shortens one lifetime to match the function signature such that the function can just assume both references have the same lifetime.