我试图通过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`

上面的结论是有效的,因为编译器可以推断i被完全替换.所以从这一点开始,i的生命周期 是&10而不是&x.


让我们用一个更简单的例子来理解为什么你的例子不起作用.

让我们考虑一下Vec<&i32>.一切都保持不变,但我们使用.push().clear()代替索引.

如果我们取而代之的是.push(&x)个,那么这个例子起作用了吗?如果我们先做.clear(),然后做.push(10),这样行吗?

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(),编译器并不知道,其中的index会延长容器的生命周期 .

这也是编译器在第一个示例中知道的原因.是因为point被重新分配,因此它从该点开始接收新的生命周期.然而,调用fn(&mut self, usize)方法并不能说明这一点.


从理论上讲,编译器中可能有一个特殊情况,当使用常量索引时,它将在此场景中延长容器的生命周期.

然而,这样的特例可能很快就会令人困惑.从现在开始,如果你把一个常量1换成一个index变量.然后,容器的生命周期 可能会突然发生巨大变化.

// With a special case, this would then pass
point[1] = &x;

// Whereas this would fail
let i = 1;
point[i] = &x;

此外,更有可能的情况是有人正在使用index变量对容器进行索引.因此,这种特殊情况也很少会起作用.

Rust相关问答推荐

在Rust中创建可变片段的可变片段的最有效方法是什么?

如何导出 rust 色二进制文件中的符号

用 rust 蚀中的future 展望 struct 的future

使用Py03从Rust调用Python函数时的最佳返回类型

Rust从关联函数启动线程

从管道读取后重置标准输入

我可以用 Rust 编写一个不可变变量

在1.5n次比较中找到整数向量中的最大和次大整数

max(ctz(x), ctz(y)) 有更快的算法吗?

(let b = MyBox(5 as *const u8); &b; ) 和 (let b = &MyBox(5 as *const u8); ) 之间有什么区别

如何使用泛型满足 tokio 异步任务中的生命周期界限

Rust Serde 为 Option:: 创建反序列化器

为什么 Rust 允许写入不可变的 RwLock?

为什么在 macOS / iOS 上切换 WiFi 网络时 reqwest 响应会挂起?

将文件的第一行分别读取到文件的其余部分的最有效方法是什么?

如何构建包含本地依赖项的 docker 镜像?

如何用另一个变量向量置换 rust simd 向量?

为什么这个 Trait 无效?以及改用什么签名?

加入动态数量的期货

在特征中返回一个 Self 类型的值