如何防止值被移动?

时间:2017-01-15 17:29:17

标签: rust move lifetime

我尝试解决the robot simulator Exercism exercise时有很多乐趣,但我面临一个价值感动的问题,我似乎无法想出一个优雅的解决方案:

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
    }

我收到此错误:

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

我认为我收到了错误,因为advance()会返回self,但我不明白为什么价值仍在移动,因为它在一个区块内使用。我真的必须实现Copy还是我错过了一生的用例?

2 个答案:

答案 0 :(得分:4)

  

我认为我得到了错误,因为advance()返回self?

不,您收到该错误是因为advance 消费 self(您的其他方法也是如此)。

您的问题的惯用解决方案几乎肯定是让您的方法采用可变引用(&mut)到self,而不是按值self。例如。签名pub fn turn_right(mut self) -> Self将成为pub fn turn_right(&mut self)(注意后者不会返回任何内容)。您可以通过引用操纵机器人的状态,并且instructions函数应该可以正常工作。

如果出于某种原因,您希望继续让方法按值self取值,则可以按如下方式重写instructions

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
}

即。继续按值传递机器人的状态,但确保在每次循环迭代时新状态都绑定到变量。 (我没有尝试编译此代码,但原则应该是合理的。)

答案 1 :(得分:1)

查看其他用户的答案,您实际上可以使用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")
        }
    })
}

似乎继续将机器人移回范围。