我试图通过《Programming Rust》一书来理解生命周期,并在这里制作了一个自定义示例:
fn simple_fn(point: [&i32; 3]) -> (&i32, &i32) {
(point[0], point[2])
}
fn main() {
let mut point: [&i32; 3] = [&19, &18, &17];
{
let x = 3;
point[1] = &x;
point[1] = &10;
}
let t = simple_fn(point);
println!("{:?}", t);
}
编译器返回错误:
error[E0597]: `x` does not live long enough
--> src/main.rs:10:20
|
9 | let x = 3;
| - binding `x` declared here
10 | point[1] = &x;
| ^^ borrowed value does not live long enough
11 | point[1] = &10;
12 | }
| - `x` dropped here while still borrowed
13 |
14 | let t = simple_fn(point);
| ----- borrow later used here
我不明白,当我将
point[1]
重新分配给&10
时,在将其分配给x
之后,那么为什么point[1]
的生命周期仍然限于x
的生命周期?
我认为困惑来自以下事实:
let mut point = &1;
{
let x = 3;
point = &x;
point = &10;
}
println!("{:?}", point); // Prints `10`
以上是有效的,因为 Rust 可以推断
i
已被完全替换。所以i
可以拥有&10
的生命周期,而不是&x
。
让我们用一个更容易理解的例子来演示为什么你的例子不起作用。
让我们考虑一个
Vec<&i32>
。一切保持不变,但我们不使用索引,而是使用 .push()
。
let mut point = Vec::new();
{
let x = 3;
point.push(&x);
point.clear();
point.push(&10);
}
println!("{:?}", point);
上面的代码可以编译吗?
不,它会导致与您遇到的错误完全相同的错误。为什么?嗯,现在可能更清楚了。是的,我们调用
.clear()
会导致 &x
被删除。然而,仅仅通过查看 clear()
的函数定义,编译器并不知道这一点。因此,与 Vec<&i32>
相关的生命周期仍然是编译器的最短(观察到的)生命周期,即 &x
的生命周期。
现在,当你这样做时:
points[1] = &x;
这实际上只是语法糖:
*point.index_mut(1) = &x;
再次强调,编译器并不知道,某些 fn index_mut()
会延长容器的生命周期。理论上,编译器中完全可能存在特殊情况,在您的情况下,当使用常量索引时,它可以延长容器的生命周期。然而,使用一些动态值来索引是更常见的,因此特殊情况最终可能会变得更加混乱。