问题
I'm having a lot of fun trying to solve the robot simulator Exercism exercise, but I'm facing a value moving problem for which I don't seem to be able to come up with an elegant solution:
impl Robot {
pub fn new(x: isize, y: isize, d: Direction) -> Self {
Robot { position: Coordinate { x: x, y: y }, direction: d }
}
pub fn turn_right(mut self) -> Self {
match self.direction {
// ...
};
self
}
pub fn turn_left(mut self) -> Self {
match self.direction {
// ...
};
self
}
pub fn advance(mut self) -> Self {
match self.direction {
// ...
};
self
}
pub fn instructions(self, instructions: &str) -> Self {
for instruction in instructions.chars() {
match instruction {
'A' => { self.advance(); },
'R' => { self.turn_right(); },
'L' => { self.turn_left(); },
_ => {
println!("{} is not a valid instruction", instruction);
},
};
}
self
}
I get this error :
enter code hereerror[E0382]: use of moved value: `self`
--> src/lib.rs:60:26
|
60 | 'A' => { self.advance(); },
| ^^^^ value moved here in previous iteration of loop
|
= note: move occurs because `self` has type `Robot`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `self`
--> src/lib.rs:61:26
|
60 | 'A' => { self.advance(); },
| ---- value moved here
61 | 'R' => { self.turn_right(); },
| ^^^^ value used here after move
|
= note: move occurs because `self` has type `Robot`, which does not implement the `Copy` trait
I think I get the error because advance()
returns self
, but I don't understand why the value is still moved as it's used inside a block. Do I really have to implement Copy
or am I missing a lifetime use case?
回答1:
I think I get the error because advance() returns self ?
No, you're getting that error because advance
consumes self
(and your other methods do, too).
The idiomatic solution to your problem is almost certainly to have your methods take a mutable reference (&mut
) to self
instead of taking self
by value. E.g. the signature pub fn turn_right(mut self) -> Self
would become pub fn turn_right(&mut self)
(note that the latter does not return anything). You can manipulate the robot's state through the reference, and your instructions
function should work fine.
If for some reason you want to continue to have the methods take self
by value, you could rewrite instructions
as follows:
pub fn instructions(self, instructions: &str) -> Self {
let mut robot = self;
for instruction in instructions.chars() {
robot = match instruction {
'A' => { robot.advance() },
'R' => { robot.turn_right() },
'L' => { robot.turn_left() },
_ => {
println!("{} is not a valid instruction", instruction);
robot
},
};
}
robot
}
I.e. continue passing the robot's state by value, but make sure that the new state is bound to a variable at every loop iteration. (I've not tried to compile this code, but the principle should be sound.)
回答2:
Looking at the other users answers, you can actually do it with fold :
pub fn instructions(self, instructions: &str) -> Self {
instructions.chars().fold(self, |robot, c| {
match c {
'L' => robot.turn_left(),
'R' => robot.turn_right(),
'A' => robot.advance(),
_ => panic!("unexpected char")
}
})
}
It seems to keep moving back robot into the scope.
来源:https://stackoverflow.com/questions/41664099/how-to-prevent-a-value-from-being-moved