我正在试着用铁 rust 色写俄罗斯方块。我在这个项目中有一些结构体,我想把它们当作不可变的,即使它们会变异。
我用来实现这种行为的方法是这样的:
#[derive(Debug)]
struct Example {
foo: i8
}
impl Example {
fn change(mut self) -> Self {
self.foo = 8;
self
}
}
它允许你做这样的事情:
let first = Example { foo: 0 };
let second = first.change();
println!("{:?}", second); // Example { foo: 8 }
但当你做这样的事情时,他会冲你吼
let first = Example { foo: 0 };
let second = first.change();
println!("{:?}", first); // error[E0382]: borrow of moved value: `first`
让我困惑的是,为什么这个方法有效:
#[derive(Debug)]
struct Matrix {
cells: [[char; 2]; 2]
}
impl Matrix {
fn new() -> Self {
Matrix {
cells: [['░'; 2]; 2]
}
}
fn solidify(mut self, row: usize, column: usize) -> Self {
self.cells[row][column] = '█';
self
}
}
fn main() {
let mut matrix = Matrix::new();
matrix = matrix.solidify(0, 0);
println!("{:?}", matrix); // Matrix { cells: [['█', '░'], ['░', '░']] }
}
而这个却没有
#[derive(Debug)]
struct Matrix {
cells: [[char; 2]; 2]
}
impl Matrix {
fn new() -> Self {
Matrix {
cells: [['░'; 2]; 2]
}
}
fn solidify(mut self, row: usize, column: usize) -> Self {
self.cells[row][column] = '█';
self
}
}
#[derive(Debug)]
struct Tetris {
matrix: Matrix
}
impl Tetris {
fn new() -> Self {
Tetris {
matrix: Matrix::new()
}
}
fn change(&mut self) {
self.matrix = self.matrix.solidify(0, 0);
/* -----------------------------------------
This is where it yells at me ^ */
}
}
fn main() {
let mut tetris = Tetris::new();
tetris.change();
println!("{:?}", tetris); // error[E0507]: cannot move out of `self.matrix` which is behind a mutable reference
}
Playground
这给出:
error[E0507]: cannot move out of `self.matrix` which is behind a mutable reference
--> src/main.rs:32:23
|
32 | self.matrix = self.matrix.solidify(0, 0);
| ^^^^^^^^^^^ -------------- `self.matrix` moved due to this method call
| |
| move occurs because `self.matrix` has type `Matrix`, which does not implement the `Copy` trait
|
note: `Matrix::solidify` takes ownership of the receiver `self`, which moves `self.matrix`
--> src/main.rs:13:21
|
13 | fn solidify(mut self, row: usize, column: usize) -> Self {
| ^^^^
我做了一些研究,我觉得要么std::mem::swap,要么std::mem::take,要么std::mem::replace,
可以帮我,但我不知道怎么做。
1条答案
按热度按时间8ulbf1ek1#
你说得对,
mem::[take,replace]()
可以完成这项工作。问题是,* 虽然你可以让变量暂时不初始化,但你不能让可变引用暂时不初始化(通过移出它),即使你在*之后重新分配它。
这种限制是有原因的:如果
matrix.solidify()
出现异常,我们将退出而不执行对matrix
的循环赋值。稍后,我们可以从异常中恢复,并观察moved-frommatrix
。如果没有依赖项(和不安全代码),唯一的解决方案是即使在重新赋值时也留下一些东西,这样即使我们恐慌
matrix
也能保持初始化。如果Matrix
实现Default
,std::mem::take()
可以帮助实现这一点--它保留默认值,而更通用的std::mem::replace()
可以帮助实现这一点--它保留 * 一些 * 值:或者:
如果这对你来说还不够好(例如,因为你没有一个好的默认值来插入,或者因为性能要求),你可以使用
replace_with
crate,它提供了replace_with::replace_with_or_abort()
,在死机的情况下,它只会中止整个进程,阻止恢复的可能性:请注意,您实际上可能需要interior mutability,而不是您现在正在做的事情。