当输入非常清楚时,为什么借用检查器需要输出的生命周期标签?

Paw*_*mar 1 lifetime rust borrow-checker borrowing

为什么借用检查器会对下面代码中的生命周期感到困惑

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
}
Run Code Online (Sandbox Code Playgroud)
| 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`
Run Code Online (Sandbox Code Playgroud)

为什么这个代码会发生什么?我错过了一些非常重要的边缘案例吗?

但是当我用生命时间标签对它们进行注释时,它可以工作.

fn func<'a>(s: &'a str, t: &'a str) -> &'a str {
    t
}
Run Code Online (Sandbox Code Playgroud)

我读到每个变量绑定(let)创建一个Implicit范围,那么2个输入变量如何具有相同的范围.纠正我,如果我知道的话.在函数调用'func'堆栈中,首先按"s"然后按"t",因此"s"和"t"具有不同的生命周期.首先删除"t",然后删除"s".

And*_*org 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"
}
Run Code Online (Sandbox Code Playgroud)

如果你不写,编译器可以假设最后一个不是你想要的'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);
}
Run Code Online (Sandbox Code Playgroud)

如果编译器允许你调用from_t而不是from_s,那么你将打印一个已经被释放的字符串.

  • @coredump函数的类型应该封装所有关于如何调用和不调用的内容.如果你必须在实现中查看如何调用它,那么实现将成为公共接口的一部分; 对实现的每次更改都会成为可能向后兼容的变更.并且无法再指定具有多种潜在实施的特征.基本上,这会很糟糕. (2认同)