我一直试图了解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;
}
}
min()
只返回对两个引用的字符串中较短者的引用。 main()
传入两个字符串引用,其引用在不同的范围内定义。我使用了String::from()
,因此引用没有静态生命周期。程序正确打印short
。 Here is the example in the Rust Playground
如果我们引用Rustonomicon(我欣赏的是正在进行中的工作文档),我们会被告知函数签名的含义如下:
fn as_str<'a>(data: &'a u32) -> &'a str
表示功能:
引用具有生命周期的
u32
,并承诺它可以生成对str
的引用,该引用可以存活一段时间。
现在让我们转到我的例子min()
的签名:
fn min<'a>(a: &'a str, b: &'a str) -> &'a str
这更受欢迎,因为:
a
有效期更长)。使用与上述引用语句类似的措辞,min()
的函数签名是什么意思?
该函数接受两个引用,并承诺生成对str
的引用,该引用只要a
和 {的引用就可以存在{1}}?以某种方式感觉不对,好像我们从b
返回对b
的引用,然后很明显该引用在min()
的生命周期内无效a
。
该函数接受两个引用,并承诺生成对main()
的引用,该引用只要str
和<的两个指示对象中的较短者即可生存/ em> a
?这可能有效,因为b
和a
的指示对象在b
的内部范围内仍然有效。
还有其他什么?
总而言之,我不明白将main()
的两个输入引用的生命周期绑定到同一生命周期,当它们的引用在被调用者的不同范围内定义时,意味着什么。
答案 0 :(得分:4)
它是(2):只要输入的生命周期较短,返回的引用就会存在。
但是,从功能的角度来看,两个输入生命周期实际上都是相同的(都是'a
)。因此,a
的变量main()
显然比b
更长,这是如何工作的?
诀窍是调用者缩短了两个引用之一的生命周期,以匹配min()
的函数签名。如果您有参考&'x T
,则可以将其转换为&'y T
iff 'x
超过'y
(也写为:'x: 'y
) 。这具有直观意义(我们可以缩短参考的生命周期而不会产生不良后果)。编译器自动执行此转换。所以想象编译器会将你的main()
变成:
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));
// ^^^^^^^^^^^^^^^^^^
}
这与名为子类型的内容有关,您可以在this excellent answer中详细了解这一点。
总结:调用者缩短一个生命周期以匹配函数签名,以便函数可以假设两个引用具有相同的生命周期。
答案 1 :(得分:2)
我要去(3)别的东西!
使用您的功能签名:
fn min<'a>(a: &'a str, b: &'a str) -> &'a str { ...}
// ...
min(&a, &b)
'a
不借来的对象的生命周期。它是由编译器为此调用生成的新生命周期。只要呼叫需要,a
和b
将被借用(或可能重新借用),并由返回值的范围扩展(因为它引用相同的'a
)。 / p>
一些例子:
let mut a = String::from("short");
{
let mut b = String::from("a long long long string");
// a and b borrowed for the duration of the println!()
println!("{}", min(&a, &b));
// a and b borrowed for the duration of the expression, but not
// later (since l is not a reference)
let l = min(&a, &b).len();
{
// borrowed for s's scope
let s = min(&a, &b);
// Invalid: b is borrowed until s goes out of scope
// b += "...";
}
b += "..."; // Ok: b is no longer borrowed.
// Borrow a and b again to print:
println!("{}", min(&a, &b));
}
正如您所看到的,任何单个调用的'a
都与借用的实际a
和b
的生命周期不同,但当然两者都必须比生成的生命周期更长每次通话。
答案 2 :(得分:1)
除了@Lukas在答案中提到的内容之外,您还可以将函数的签名读取为 - 返回的引用有效,直到两个传递的引用都有效,即它之间的连接(又称AND)参数寿命。
还有更多内容。以下是两个代码示例:
let a = String::from("short");
{
let c: &str;
let b = String::from("a long long long string");
c = min(&a, &b);
}
和
let a = String::from("short");
{
let b = String::from("a long long long string");
let c: &str;
c = min(&a, &b);
}
第一个不起作用(第二个不起作用)。似乎b
和c
的生命周期与相同范围内的生命周期相同,但范围中的排序也很重要,因为第一种情况b
生命周期将在{{1}之前结束}}