为什么下面的代码中的借用检查器对生存期感到困惑
fn main() {
let ss = "abc"; // lets say 'a scope
let tt = "def"; // lets say 'b scope
let result = func(ss, tt);
}
fn func(s: &str, t: &str) -> &str {
t
}
| fn func(s: &str, t: &str) -> &str {
| ^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `s` or `t`
为什么这段代码中的内容无关紧要?我是否缺少一些非常重要的优势案例?
但是当我用生命标签注释它们时,它会起作用。
fn func<'a>(s: &'a str, t: &'a str) -> &'a str {
t
}
我读到每个变量绑定(let)都创建一个隐式作用域,那么2个输入变量为何具有相同的作用域。纠正我,如果我很疲倦。在函数调用“ func”堆栈中,先按“ s”,然后按“ t”,因此,“ s”和“ t”具有不同的生存期。首先删除“ t”,然后删除“ s”。
答案 0 :(得分:6)
您尚未告诉编译器返回值是否可以从s
,t
,两者或两者都不借用:
fn from_s<'a, 'b>(s: &'a str, t: &'b str) -> &'a str {
// can be abbreviated: fn from_s<'a>(s: &'a str, t: &str) -> &'a str
s
}
fn from_t<'a, 'b>(s: &'a str, t: &'b str) -> &'b str {
// can be abbreviated: fn from_t<'a>(s: &str, t: &'a str) -> &'a str
t
}
fn from_both<'a>(s: &'a str, t: &'a str) -> &'a str {
if s < t {
s
} else {
t
}
}
fn from_neither<'a, 'b>(s: &'a str, t: &'b str) -> &'static str {
// can be abbreviated: fn func(s: &str, t: &str) -> &'static str
"foo"
}
如果您未编写'static
,则编译器可以假定最后一个不是您想要的。但是您仍然需要在前三个之间消除歧义。
要了解差异为何如此重要,请考虑像这样的呼叫者
fn main() {
let s = String::from("s");
let r;
{
let t = String::from("t");
r = from_s(&s, &t);
// t goes out of scope
}
println!("{}", r);
}
如果编译器允许您调用from_t
而不是from_s
,则您将打印已经释放的字符串。
答案 1 :(得分:1)
如果我理解正确,那么问题是“为什么两个参数的寿命相同?”简短的答案是,生存期注释不是具体值,而是 bounds -它指出“此值的生存期不得超过此生存期。” / p>
当您按照有问题的方式编写代码时,fn func<'a>(s: &'a str, t: &'a str) -> &'a str
的意思是:
'a
,每个呼叫站点上的寿命可以不同。s
和t
的生存时间必须不少于 而不是'a
(对于字符串文字,情况总是如此,因为它们是{{1 }},但对于强制{{1}的'static
而言可能不成立)-也就是说,函数类型在参数类型上是 contra 变量(而生存期是类型的一部分) )。&String
-函数类型在返回类型上 co </ strong>。(有关方差的更多信息,请参见Rustonomicon)
简化,这意味着两个参数都必须超过返回值。这并不总是您想要的-考虑以下情况(请注意,我现在返回&str
,这样初始化顺序就不会改变):
'a
此代码虽然在逻辑上是正确的,但不会编译,因为生命周期注释与逻辑不一致:第二个参数s
绝不与返回值连接,但它限制了返回值根据功能注释,其寿命。但是当我们将功能更改为以下内容时:
fn main() {
let ss = "abc";
let mut result = "";
{
let tt = "def".to_string();
result = func(ss, &tt);
}
println!("{}", result);
}
fn func<'a>(s: &'a str, t: &'a str) -> &'a str {
s
}
...它会编译并返回所需的结果(尽管有一些警告),因为生命周期t
与fn func<'a, 'b>(s: &'a str, t: &'b str) -> &'a str {
s
}
无关,实际上,它可以完全删除-终生淘汰会很好地工作。