如何防止值被移动?

Posted

技术标签:

【中文标题】如何防止值被移动?【英文标题】:How to prevent a value from being moved? 【发布时间】:2017-05-30 13:35:13 【问题描述】:

我在尝试解决 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 还是我错过了终生用例?

【问题讨论】:

借钱可以吗?另外,为什么不实现Copy 不要实现Copy,而是阅读the builder pattern @EliSadoff 我实际上是在尝试学习如何编写好的代码。我认为在这里复制会很糟糕,因为它会占用不必要的资源。 @wimh:代码构造看起来与我尝试构建的相似,但我没有在其中找到答案。谢谢你的链接,顺便说一句,这个页面似乎充满了很棒的东西。 【参考方案1】:

我认为我收到错误是因为 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

即继续按值传递机器人的状态,但要确保新状态在每次循环迭代时都绑定到一个变量。 (这段代码我没试过编译,但原理应该不错。)

【讨论】:

谢谢,您的第二个解决方案确实有效。我确实尝试使用引用,但我遇到了同样的问题,因为测试套件使用链接调用。如果我理解得很好,例如从 Advance 返回的 self 的事实正在移动值,但它从未移回 fn instructions 上下文? 看看其他练习用户,你实际上可以用 fold 来做: instructions.chars().fold(self, |robot, c| match c 'L' => robot.turn_left (), 'R' => robot.turn_right(), 'A' => robot.advance(), _ => panic!("unexpected char") ) @stamm 是的,这正是问题所在。一旦按值将值传递给方法,就不能再使用它。但是由于您的方法返回更改后的状态,如果您将返回值分配给变量,您可以继续使用它。【参考方案2】:

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

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

【讨论】:

以上是关于如何防止值被移动?的主要内容,如果未能解决你的问题,请参考以下文章

移动:如何防止下拉刷新

如何防止窗户被移动?

如何防止桌面网站上的图像在移动设备上加载?

如何防止 Ouibounce 出现在移动设备上?

在 UWP 应用程序中,如何防止 Gamepad 也移动插入符号?

如何防止子 QGraphicsItem 与父级一起移动?