为什么 Rust 编译器不能推断出一个参数比另一个参数更长寿?

und*_*ain 5 rust borrow-checker

我有以下代码:

struct Solver<'a> {
    guesses: Vec<&'a str>,
}

impl<'a> Solver<'a> {
    fn register_guess(&mut self, guess: &'a str) {
        self.guesses.push(guess);
    }
}

fn foo(mut solver: Solver, guess: &str) {
    solver.register_guess(guess)
}
Run Code Online (Sandbox Code Playgroud)

它不编译:

   |
11 | fn foo(mut solver: Solver, guess: &str) {
   |        ----------                 - let's call the lifetime of this reference `'1`
   |        |
   |        has type `Solver<'2>`
12 |     solver.register_guess(guess)
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
Run Code Online (Sandbox Code Playgroud)

错误消息表明该参数guess必须超过生存期solver。对我来说很明显这是真的:solverends的生命周期在函数的末尾,而of的生命周期则guess不然。这似乎是编译器应该能够推断出来的,并且编译时不会出错。

为什么不是这样呢?这段代码真的有办法solver继续存在吗guess?或者只是编译器根本不尝试进行这种推理?

我知道如何修复它 --- 将功能更改为fn foo<'a>(mut solver: Solver<'a>, guess: &'a str)--- 但我问为什么我必须这样做。

use*_*342 6

虽然solver它本身无法存活guess,但它所指的生命周期却可以。例如,想象一下foo()使用Solver<'static>. 这种求解器会期望猜测&'static str并可能将所引用的数据存储guess在全局变量中。(请记住,编译器不会考虑register_guess()借用检查时的作用foo(),它只考虑其签名。)

更一般地说,可能包含对比自身寿命更长的数据的Solver<'a>引用。没有什么可以阻止将猜测的内容存储在此类引用中。如果不能保证至少活到,那么就根本不合理。例如,采用以下替代定义:'asolverregister_guess()guess'afoo()Solver

struct Solver<'a> {
    guesses: &'a mut Vec<&'a str>,
}
Run Code Online (Sandbox Code Playgroud)

如果 , 的签名未更改register_guess()foo()将允许出现如下不健全的代码:

fn main() {
    let mut guesses = vec![];
    let solver = Solver { guesses: &mut guesses };
    {
        let guess = "foo".to_string();
        // stores temporary "foo" to guesses, which outlives it
        foo(solver, guess.as_str());
    }
    println!("{}", guesses[0]); // UB: use after free
}
Run Code Online (Sandbox Code Playgroud)