如何交换结构的两个字段
How to swap two fields of a struct
我已经开始学习 Rust,并且正在尝试实现一个简单的一维元胞自动机。我想将自动机状态 (Board
) 表示为包含大小和两个不同向量(相同大小)的结构。我试过了:
struct Board {
n: usize,
cur: Vec<u32>,
next: Vec<u32>,
}
impl Board {
fn new(size: usize) -> Board {
Board {
n: size,
cur: vec![0;size],
next: vec![0;size],
}
}
}
到目前为止一切顺利。我也能够改变这两个向量。但是后来我希望能够交换两个向量(或者更确切地说是它们的引用),例如:
fn swap(&mut self) -> &Board {
let tmp = self.cur;
self.cur = self.next;
self.next = tmp;
self
}
它失败了,cannot move out of borrowed content [E0507]
我想我能理解。我还尝试了 mem::swap
,我在类似标题的问题中找到了它,但没有成功。
我怎样才能让这个例子起作用? (由于我是 Rust 的初学者,请不要犹豫建议不同的数据表示)。
如您所见,mem::swap
是要走的路:
fn swap(&mut self) -> &Board {
std::mem::swap(&mut self.cur, &mut self.next);
self
}
这行得通。请注意,当使用 .
时,您正在取消引用 self
。因此,虽然 self
的类型为 &mut Board
,但 self.cur
的类型为 Vec<u32>
。因此编译器抱怨 "move out of borrowed content" 而我们需要额外的 &mut
s.
What's the problem?
您在数据中打孔:
fn swap(&mut self) -> &Board {
let tmp = self.cur; // 1
self.cur = self.next; // 2
self.next = tmp; // 3
self
}
如果我们逐行分析:
self.cur
现在未初始化
self.next
现在未初始化
- 一切都再次符合犹太洁食标准
如果在第 (3) 行发生变化以收紧情况之前由于某种原因计算被中断,self
现在中毒并可能导致各种讨厌的事情发生。值得注意的是,它的析构函数可能会尝试释放内存两次。
理论上,您可以让编译器检查临时漏洞并毫无疑问地证明:
- 打孔时没有函数访问
self
- 到了作用域的尽头,不管是正常到达还是展开,空洞又被填满了
确实在某些时候它被考虑过......但事实是它很复杂并且有现成的解决方法。
So?
答案在于 std::mem
,它公开了以安全方式执行此类低级操作的功能。虽然函数本身是使用 unsafe
在幕后实现的,但它们依靠对语言和运行时的理解来公开安全接口。
您会感兴趣的两个特定函数是:
replace
:将dest: &mut T
的内容替换为src: T
和returns之前包含在dest
后面的内容
swap
: 交换其参数的内容
使用这两个简单而安全的原语,您可以避免在数据中打孔。
我已经开始学习 Rust,并且正在尝试实现一个简单的一维元胞自动机。我想将自动机状态 (Board
) 表示为包含大小和两个不同向量(相同大小)的结构。我试过了:
struct Board {
n: usize,
cur: Vec<u32>,
next: Vec<u32>,
}
impl Board {
fn new(size: usize) -> Board {
Board {
n: size,
cur: vec![0;size],
next: vec![0;size],
}
}
}
到目前为止一切顺利。我也能够改变这两个向量。但是后来我希望能够交换两个向量(或者更确切地说是它们的引用),例如:
fn swap(&mut self) -> &Board {
let tmp = self.cur;
self.cur = self.next;
self.next = tmp;
self
}
它失败了,cannot move out of borrowed content [E0507]
我想我能理解。我还尝试了 mem::swap
,我在类似标题的问题中找到了它,但没有成功。
我怎样才能让这个例子起作用? (由于我是 Rust 的初学者,请不要犹豫建议不同的数据表示)。
如您所见,mem::swap
是要走的路:
fn swap(&mut self) -> &Board {
std::mem::swap(&mut self.cur, &mut self.next);
self
}
这行得通。请注意,当使用 .
时,您正在取消引用 self
。因此,虽然 self
的类型为 &mut Board
,但 self.cur
的类型为 Vec<u32>
。因此编译器抱怨 "move out of borrowed content" 而我们需要额外的 &mut
s.
What's the problem?
您在数据中打孔:
fn swap(&mut self) -> &Board {
let tmp = self.cur; // 1
self.cur = self.next; // 2
self.next = tmp; // 3
self
}
如果我们逐行分析:
self.cur
现在未初始化self.next
现在未初始化- 一切都再次符合犹太洁食标准
如果在第 (3) 行发生变化以收紧情况之前由于某种原因计算被中断,self
现在中毒并可能导致各种讨厌的事情发生。值得注意的是,它的析构函数可能会尝试释放内存两次。
理论上,您可以让编译器检查临时漏洞并毫无疑问地证明:
- 打孔时没有函数访问
self
- 到了作用域的尽头,不管是正常到达还是展开,空洞又被填满了
确实在某些时候它被考虑过......但事实是它很复杂并且有现成的解决方法。
So?
答案在于 std::mem
,它公开了以安全方式执行此类低级操作的功能。虽然函数本身是使用 unsafe
在幕后实现的,但它们依靠对语言和运行时的理解来公开安全接口。
您会感兴趣的两个特定函数是:
replace
:将dest: &mut T
的内容替换为src: T
和returns之前包含在dest
后面的内容
swap
: 交换其参数的内容
使用这两个简单而安全的原语,您可以避免在数据中打孔。