2017-02-15 1 views
4

변경할 수있는 반복자를 지원하는 장난감 컨테이너 클래스를 디자인하고 싶지만 반복기의 수명과 컨테이너에 대한 참조를 정렬하는 데 문제가 있습니다.변경 가능한 반복자를 지원하는 컨테이너를 구현하려면 어떻게해야합니까?

나는 최소한의 비 컴파일 예제를 만들려고했습니다

struct Payload { 
    value: i32, 
} 

struct Container { 
    val: Payload, 
} 

struct IterMut<'a> { 
    cont: &'a mut Container, 
    cnt: i32, 
} 

impl<'a> Container { 
    fn new() -> Container { 
     Container { val: Payload { value: 42 } } 
    } 
    fn iter_mut(&'a mut self) -> IterMut<'a> { 
     IterMut { 
      cont: self, 
      cnt: 10, 
     } 
    } 
} 

impl<'a> Iterator for IterMut<'a> { 
    type Item = &'a mut Payload; 

    fn next<'b>(&'b mut self) -> Option<Self::Item> { 
     self.cnt -= 1; 

     if self.cnt < 0 { 
      return None; 
     } else { 
      Some(&mut self.cont.val) 
     } 
    } 
} 

fn main() { 
    let mut cont = Container::new(); 

    let mut it = cont.iter_mut(); 
    it.next(); 
} 

iter_mut()을 사용하여 이상 반복 할 때 동일한 항목 10 번을 반환하는 진짜 바보 컨테이너를 구현하기위한 것입니다.

Iterator::next을 구현하는 방법을 알 수 없습니다. 나는 그것이 Iterator::next을 구현하기 위해 적응 관리 할 수 ​​있기 때문에,

fn manual_next<'a, 'b>(i: &'a mut IterMut<'b>) -> Option<&'a mut Payload> { 
    i.cnt -= 1; 

    if i.cnt < 0 { 
     return None; 
    } else { 
     Some(&mut i.cont.val) 
    } 
} 

이 도움이되지 않습니다

은 내가 next 원하는 것과 같은 의미를 구현하는 일반 함수를 작성 관리 않았다 그리고 Iterator을 구현하지 않고서도 for-loops에서 컨테이너를 반복 할 수 없습니다.

답변

5

반복자를 그대로 구현할 수 없습니다. 동일한 항목에 대한 하나 이상의 변경 가능한 참조를 가져 와서 Rust의 별칭/차용 규칙을 위반할 수 있기 때문입니다. 차용 검사기가 오류를 잡았습니다. :-)

예를 들어, main 예 확장 :

fn main() { 
    let mut cont = Container::new(); 

    let mut it = cont.iter_mut(); 
    let alias_1 = it.next(); 
    let alias_2 = it.next(); 
    // alias_1 and alias_2 both would have mutable references to cont.val! 
} 

다른 iter_mut 반복자 (벡터/슬라이스에 하나 하나 예를 들어) 각 단계에서 다른 항목에 대한 참조를 반환, 그래서 것은 없습니다 이 문제.

논리적으로 변경할 수있는 부분을 반복 처리해야하는 경우, 실수로 반복 할 수 있지만 RefCell 또는 Cell을 통해 내부 변경을 사용할 수 있습니다.

manual_next 함수가 컴파일되는 이유는 사용자가 Iterator::next 서명에 제약을받지 않기 때문에 실제로 한 번만 호출하면 안전합니다 (결과를 유지하지 않으면 더 이상).

let mut cont = Container::new(); 

let mut it = cont.iter_mut(); 
let x = manual_next(&mut it); 
manual_next(&mut it); // Error: `it` is still borrowed mutably 
대조적으로

Playground

, Iterator::nextcollect가에 보내고 같은 일을하게하는 유형이 : 당신이 결과를 저장하려고하면 그러나, IterMut가 mutably 차용하고 다시 호출 할 수 유지 가능한 벡터.

+0

물론 아하! 그래서 아주 간단한 예제를 만들려고했을 때 실수로 잘못된 예제를 만들었습니다. –

+0

내 "수동"next-method가 작동하는 이유는 시그니처가 다음부터 하나 이상의 반환 값을 동시에 가질 수 없기 때문입니다. Iterator-trait의 next-method에 대한 서명이하는 반면? Iterator 특성은 next()가 동일한 변경 가능한 참조를 두 번 반환하지 않는다고 약속합니다. 하지만 제 구현은 그 일을하려고했습니다. –

+1

네, 맞습니다. 나는 그것을 커버하려고 내 대답에 약간을 추가했습니다. –

관련 문제