Rust 如何防止值被移动?

Rust 如何防止值被移动?,rust,move,lifetime,Rust,Move,Lifetime,我在尝试解决这个问题时很开心,但我面临着一个价值转移问题,我似乎无法想出一个优雅的解决方案: 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 {

我在尝试解决这个问题时很开心,但我面临着一个价值转移问题,我似乎无法想出一个优雅的解决方案:

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
    }
我得到这个错误:

在此输入代码错误[E0382]:使用移动值:`self`
-->src/lib.rs:60:26
|
60 |'A'=>{self.advance();},
|^^^^值在循环的上一次迭代中移到此处
|
=注意:发生移动是因为'self'的类型为'Robot',而该类型不实现'Copy'特性
错误[E0382]:使用移动值:`self`
-->src/lib.rs:61:26
|
60 |'A'=>{self.advance();},
|----值移到了这里
61 |'R'=>{self.turn_right();},
|^^^^^移动后此处使用的值
|
=注意:发生移动是因为'self'的类型为'Robot',而该类型不实现'Copy'特性
我想我得到这个错误是因为
advance()
返回
self
,但我不明白为什么值在块中使用时仍然被移动。我真的必须实现
Copy
吗?还是我错过了一个终生的用例

我想我得到这个错误是因为advance()返回self

不,您得到该错误是因为
advance
消耗
self
(您的其他方法也一样)

解决问题的惯用方法几乎肯定是让您的方法对
self
进行可变引用(
&mut
),而不是按值对
self
进行引用。例如,签名
pub-fn-turn\u right(mut-self)->self
将变成
pub-fn-turn\u right(&mut-self)
(请注意,后者不会返回任何内容)。您可以通过参考操纵机器人的状态,您的
指令
功能应该可以正常工作

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

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
}
也就是说,继续按值传递机器人的状态,但确保新状态在每次循环迭代时绑定到一个变量。
(我没有试着编译这段代码,但原则应该是合理的。)

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

它似乎一直在把机器人移回范围。

你能借用一下吗?另外,为什么不实现
Copy
?不要实现
Copy
,但要了解@EliSadoff,我实际上在努力学习如何编写好代码。我认为在这里复制是不好的,因为它会占用不必要的资源。@wimh:代码结构与我试图构建的代码结构相似,但我没有从中找到答案。谢谢你的链接,顺便说一句,这个页面似乎充满了伟大的东西。谢谢你,你的第二个解决方案确实奏效了。我确实尝试使用引用,但我遇到了同样的问题,因为测试套件使用链接调用。如果我能很好地理解,例如,从advance返回的
self
正在移动值,但它从未被移回
fn指令
上下文?看看其他exercism用户,您实际上可以使用fold:instructions.chars().fold(self,| robot,c{match c{'L'=>robot.turn_left(),'R'=>robot.turn_right(),'A'=>robot.advance(),=>panic!(“意外字符”)})@stamm是的,这正是问题所在。一旦你将一个值逐个传递给一个方法,你就不能再使用它了。但是由于你的方法返回的是已更改的状态,如果你将返回值赋给一个变量,你可以继续使用它。