Rust 能自动推断出所有的lifetime吗?

答: 不能。

我觉得前面的回答都不能解决这位题主的疑惑 。我想了一个有点绕的例子,来说明编译器是不能自动推断出generic lifetime的,因为可行的标注方法不只一种(楼上那个longest例子从逻辑上看似乎只剩下一种标注方法了,所以不具有足够的说服力)。

如下面定义的函数根据短字符串的长度来截取长字符串,该函数因为没有标注lifetime无法成功编译:

fn cut_long_according_to_short(l: &str, s: &str) -> &str {
    let len = s.len();
    &l[0..len]    
}

有两种不同的标注方法可以实现成功编译,编译器无法自动推断出该采用哪一个。

第一种比较宽松:

fn cut_long_according_to_short<'a>(l: &'a str, s: &str) -> &'a str {
    let len = s.len();
    &l[0..len]    
}

第二种比较严格:

fn cut_long_according_to_short<'a>(l: &'a str, s: &'a str) -> &'a str {
    let len = s.len();
    &l[0..len]    
}

但是两者最终实现的语义是有区别的。后者不仅要求返回引用的lifetime不得超过l,而且要求也不得超过s

我们可以验证这二者的区别。例如我们会发现如果采用第一种宽松的标注法,下面的代码是可以成功编译的;反之如果采用第二种严格的标注法,则下面的代码无法编译:


fn main() {
    let result;    

    let string1 = String::from("The loooooooong");
    let l = string1.as_str();

    {
        let string2 = String::from("The short");
        let s = string2.as_str();

        result = cut_long_according_to_short(l, s);
    }
    
    println!("{result}");
    
}

这是由于string2的lifetime小于result,在println!行运行前就被drop掉了(注意string2被括号{}限定在一个更小的scope内)。这在第一种较宽松的标注中是被允许的,而被第二种严格的标注所禁止。