2017-01-15 3 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 
    } 

I을 이 오류를 얻을 :

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

차용 하시겠습니까? 또한 '복사'를 구현하지 않는 이유는 무엇입니까? –

+1

'Copy'를 구현하지 말고 [빌더 패턴] (https://aturon.github.io/ownership/builders.html)을 읽으십시오. – wimh

+0

@EliSadoff 실제로 좋은 코드를 작성하는 방법을 배우려고합니다. 나는 불필요하게 자원을 필요로하기 때문에 여기서 복사하는 것이 좋지 않을 것이라고 생각한다. – stamm

답변

4

advance()가 자체를 반환하기 때문에 오류가 발생한다고 생각하십니까?

advanceself를 소비 (그리고 다른 방법도 할) 때문에 아니, 당신은 그 오류가 있습니다.

문제의 관용적 인 해결 방법은 거의 self을 값으로 사용하는 대신 변경 가능한 참조 (&mut)를 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 
} 

, 즉 계속해서 로봇의 상태를 값으로 전달하지만 모든 루프 반복마다 새 상태가 변수에 바인딩되는지 확인하십시오. (. 나는이 코드를 컴파일 시도하지했지만, 원칙 소리이어야 함)

+0

두 번째 솔루션이 실제로 작동했습니다. 참조를 사용하려고 시도했지만 테스트 스위트에서 연결 호출을 사용하기 때문에 동일한 문제가 발생했습니다. 만약 내가 잘 이해했다면 반환 된'self'가 예를 들어 진보했다는 사실이 값을 움직이는 것이었지만'fn instructions' 문맥으로 되돌아 가지 않았습니다. – stamm

+0

다른 운동 사용자를 보면 실제로 접을 수 있습니다. 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") 
     } 
    }) 
} 

유지하는 것 로봇을 다시 스코프로 이동.

관련 문제