与 Rust 勾心斗角 · 快没有爱了

基于 Rust 的 Vec 容器,可以表达数学里的 n 维点。下面的 foo 函数可以根据两个 n 维点 a 和 b,构造一个点集 {a, b, c},其中 c 是 a 和 b 的中点。

fn foo(a: &Vec, b: &Vec) -> Vec> { assert_eq!(a.len(), b.len()); let mut c: Vec = Vec::new(); for i in 0 .. a.len() { c.push(0.5 * (a[i] + b[i])); } let mut points: Vec> = Vec::new(); points.push(a.clone()); points.push(b.clone()); points.push(c); return points; }

注意,points 存储的是 ab 的副本,并非 ab 本身。倘若我希望 points 里存储的是 ab 本身,该如何做呢?我能想到的方案是
fn foo(a: &Vec, b: &Vec) -> Vec<&Vec> { assert_eq!(a.len(), b.len()); let mut c: Vec = Vec::new(); for i in 0 .. a.len() { c.push(0.5 * (a[i] + b[i])); } let mut points: Vec<&Vec> = Vec::new(); points.push(a); points.push(b); points.push(&c); return points; }

现在,points 存储的是 abc 的引用,但是 rustc 在编译这段代码时,会报错并指出,这个函数的返回值包含了一个借用值,但是函数签名却未能指明借用的是 a 还是 b。虽然代码写的很明白,ab 都被借用了,但即便如此,rustc 依然无法确定在 points 生命周期之内 ab 是否仍然健在,因此需要通过生命周期标记告诉 rustc,a 以及 b 的生命周期至少与 points 一样长,亦即
fn foo<'a>(a: &'a Vec, b: &'a Vec) -> Vec<&'a Vec> { ... ... ... }

真正致命的问题在于 c,即
points.push(&c);

rustc 在编译这行代码时,会报错:
error[E0515]: cannot return value referencing local variable `c`

意思是,不能将一个局部变量的引用放在 points 里并将其返回。因为 foo 函数结束时,c 便寿终正寢,从而导致 points 对它的引用失效。我现在无法解决这个问题,只好乖乖地回到了最初的方案,用 pointsab 所引用的点的副本,再存 c
现在,再来写一个函数 bar,用它修改 points,将 c 放在 ab 的中间:
fn bar(points: &mut Vec>) { let b = points[1]; points[1] = points[2]; points[2] = b; }

逻辑上没问题,但是 rustc 认为,
move occurs because value has type `Vec`, which does not implement the `Copy` trait

意思就是 bar 里面的三条赋值语句,都是错的,原因是,Vec 没实现 Copy Trait。要 Copy 什么呢?我只是希望 points 的第 2 个和第 3 个元素交换一下位置,并不想 Copy 什么啊。然而,我却不知道该怎样写这个函数了,倘若 points 存储的是引用,而不是实际的值,上述赋值语句应该是成立的,但是这又会导致 foo 函数难以定义。
【与 Rust 勾心斗角 · 快没有爱了】感觉对 rust 快没有爱了……好在一开始就没有。

    推荐阅读