2017-01-15 10 views
0

私は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を実装する必要がありますか、または生涯のユースケースがありませんか?

+1

借りてもらえますか?また、 'Copy'を実装してみませんか? –

+1

'Copy'を実装しませんが、[builder pattern](https://aturon.github.io/ownership/builders.html)を読んでください – wimh

+0

@EliSadoff私は実際に良いコードを書く方法を学ぼうとしています。私はここでのコピーは不必要にリソースを必要とするので悪いと思う。 – stamm

答えて

4

advance()が自己を返すため、エラーが発生すると思いますか?

advanceselfを(そして、あなたの他の方法が行う、あまりにも)消費するのでいいえ、あなたはそのエラーを取得しています。

問題の慣用的な解決方法は、ほとんどの場合、selfを値でとる代わりに、変更可能な参照(&mut)をselfに変更することです。例えば。署名pub fn turn_right(mut self) -> Selfpub 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 
} 

すなわちをロボットの状態を値渡しし続けますが、新しい状態がループの繰り返しごとに変数にバインドされていることを確認してください。 (。私はこのコードをコンパイルしようとしていませんでしたが、原理は健全でなければなりません)

他のユーザーの回答を見てみると
+0

ありがとうございました。実際に2番目の解決策が働いています。私は参照を使用しようとしましたが、テストスイートがチェーン呼び出しを使用するため、同じ問題がありました。私がよく分かっていれば、返された 'self'が例えば前進したという事実が値を動かしていたのですが、' fn instructions'文脈に戻ることはありませんでしたか? – stamm

+0

他のエクササイズユーザーを見ると、実際にfold: instructions.chars()。fold(self、| robot、c | { 'L' => robot.turn_left() 'R' => robot.turn_right()、 'A' => robot.advance()、 _ =>パニック!( "unexpected char") } } – stamm

+1

@stammはい、それはまさに問題です。メソッドに値を渡すと、それを使用できなくなります。しかし、あなたのメソッドは変更された状態を返すので、戻り値を変数に代入すると、それを使い続けることができます。 – fjh

1

、あなたが実際倍でそれを行うことができます。

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") 
     } 
    }) 
} 

続けているようですロボットをスコープに戻します。

関連する問題