2014-11-11 4 views
2

나는 순진하게도이 작업을 수행하려고 :클로저를 녹이 사용하여 반복기를 만드는 방법은 무엇입니까?

struct Foo<'a, S: Send, T:Send> { 
    next_:Box<Fn<(&'a mut S,), Option<T>> + Send>, 
    state:S 
} 

impl<'a, S: Send, T: Send> Iterator<T> for Foo<'a, S, T> { 
    fn next(&mut self) -> Option<T> { 
     return self.next_.call((&mut self.state,)); 
    } 
} 

내가 쉽게 폐쇄를 사용하여 작업에 보낼 수 반복자를 만들 수 있습니다.

그러나, 지칠대로 지친 수명 불일치 오류가 발생

<anon>:8:33: 8:48 error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements 
<anon>:8   return self.next_.call((&mut self.state,)); 
             ^~~~~~~~~~~~~~~ 
<anon>:7:5: 9:6 help: consider using an explicit lifetime parameter as shown: fn next(&'a mut self) -> Option<T> 
<anon>:7  fn next(&mut self) -> Option<T> { 
<anon>:8   return self.next_.call((&mut self.state,)); 
<anon>:9  } 
error: aborting due to previous error 
playpen: application terminated with error code 101 

내가 오류를 이해하지 않습니다.

클로저는 구조체의 수명 인 평생 'a'인수를 사용해야합니다.

상태는 struct에 의해 소유되므로 수명이 a입니다.

next_.call ((& mut self.state,))을 사용하면 작업이 호출되지 않습니다. 호출의 지속 기간 동안 만 유효해야합니다. 유효한만큼 유효해야합니다.

여기에서 불일치는 next()에서의 자기 수명과 '전화 거는 것 ...'사이에 있지만 왜 그렇게되지 않을지는 알 수 없습니다.

위의 코드를 수정하는 올바른 방법은 무엇입니까?

더 좋은 방법이 있습니까?

는 놀이 틀 : 폐쇄의 수명이 유형 서명의 일부가 될 수 없습니다해야하기 때문에 http://is.gd/hyNi0S

답변

3

이, higher-rank lifetimes이 필요합니다 폐쇄는 에 대한 &'a mut S을 원하는 모든 수명 'a (그것은을 호출해야하기 때문에 기능은 내부적으로 만 사용되도록 보장 된 데이터로 기능합니다. 외부에서 이름을 지정할 수는 없지만 형식 서명에 외부에서 노출 된 (그리고 다소 제어 가능) 것은 아닙니다. 이것은 불가능하지만 IRC에서 Niko Matsakis가 작업하는 것을 보았습니다. #18837과 같은 예비 요청이 있으므로 잘 보일 것입니다. 인 (next_은 적어도 'a을 위해 사는 참조하여 호출 할 수 있기 때문에 코드가 실패하지만, &mut self.state 만이 &'a mut self으로 선언하지 않는 한하지 'a을 어느만큼 &mut self 등을 위해 살고 :

는 명확하게하려면 왜 컴파일러가 제안하는지). 이 수명을 추가하는 것은 특성 선언의 요구 사항을 충족시키지 않기 때문에 불법입니다.

지금까지는 이전 클로저를 사용하여이 문제를 해결할 수 있습니다 (이것은 본질적으로 Fn 특성 개체가 어쨌든 무엇입니까). Unfold을위한 표준 라이브러리 유형도 있습니다.

+0

그리고 필요한 경우 Unfold 예제가 있습니다. http://www.reddit.com/r/rust/comments/2iunxo/yield_and_impl_iterator/cl5mdoh – ArtemGr

3

이것은 현재 녹의 형질 시스템의 불행한 한계이며, 곧 해제 될 것입니다. higher-kinded lifetimes이 부족합니다. 지금까지 내가 아는 한, 그 구현은 현재 진행중이다.

는 (이 덜 일반적으로하지 않습니다 내가 'static 더욱 추론을 할 수 있도록 mut을 제거했습니다)의 가까이 당신의 구조체 정의를 살펴 보자 :

struct Foo<'a, S: Send, T:Send> { 
    next_: Box<Fn<(&'a S,), Option<T>> + Send>, // ' 
    state: S 
} 

'a 수명 매개 변수는 여기 입력 매개 변수입니다. 그것은 그것이 구현 자에 의해서가 아니라 구조의 사용자에 의해 제공된다는 것을 의미합니다.

(BTW, 그것은 하지 구조 인스턴스의 수명 - 당신은 형식 매개 변수와 같은 수명을 지정할 수 없습니다, 당신은 또한 Iterator 특성 때문에 사용할 수 없습니다 self 기준에 평생이어야합니다 방법이 그러나, 단지 보조 노트입니다. 평생 매개 변수가없는, 그리고

이것은 당신의 구조의 사용자가 약간의 수명을 선택 포함 임의로을 'a를 선택할 수 있다는 것을 의미) 실제 문제와 관련이있는 구조체의 수명보다 길습니다 (예 : 'static). - 될 수있는 next() 방법에 self의 수명

struct FooStatic<S: Send, T: Send> { 
    next_: Box<Fn<(&'static S,), Option<T>> + Send>, // ' 
    state: S 
} 

갑자기 폐쇄는 분명히 아닌 경우입니다 'static 참조를 받아 들일 수 : 이제 선택이 구조 (단지 'a에 대한 'static 대체)을 변환하는 방법을 관찰 더 짧아서 그냥 닫을 수는 없습니다. 이것은 단지 (컴파일러에 의해 제안) self 수명이 'a에 해당 않은 경우 일할 수 : 앞서 말했듯이 특성 계약을 위반하기 때문에

fn next(&'a mut self) -> Option<T> 

그러나, 당신이 쓸 수 없습니다.

가 높은 kinded, 수명이 폐쇄 자체에 수명이 매개 변수를 특정 할 수있을 것이다 :

struct Foo<S: Send, T: Send> { 
    next_: Box<for<'a> Fn<(&'a mut S,), Option<T>> + Send>, 
    state: S 
} 

밀폐의 수명 파라미터는이 경우, 폐쇄 호출자에 의해 선택되는 이러한 방식으로, 그것은 Iterator 특성 (예 : 당신 :)의 구현 자이므로 next_을 참조 용으로 Foo 내부 참조를 포함하여 호출 할 수 있습니다.

0

당신이 사용하는 일반적인 특성 객체 모두를 수행 할 수 있습니다

struct IterClosure<T, C>(C) where C: FnMut() -> Option<T>; 

impl<T, C> Iterator for IterClosure<T, C> where C: FnMut() -> Option<T> 
{ 
    type Item = T; 

    fn next(&mut self) -> Option<Self::Item> { 
     (self.0)() 
    } 
} 

struct BoxedIterClosure<'a, T>(Box<FnMut() -> Option<T> + 'a>); 

impl<'a, T> Iterator for BoxedIterClosure<'a, T> 
{ 
    type Item = T; 

    fn next(&mut self) -> Option<Self::Item> { 
     (self.0)() 
    } 
} 


fn main() { 
    let mut it = (0..10).into_iter(); 
    let ic = IterClosure(|| it.next()); 

    println!("{}", ic.sum::<i32>()); 

    let mut it = (0..10).into_iter(); 
    for i in IterClosure(|| it.next()) { 
     println!("{}", i); 
    } 

    let mut it = (0..10).into_iter(); 
    let ic = BoxedIterClosure(Box::new(|| it.next())); 

    println!("{}", ic.fold(0 as i32, |s, i| s+i)); 
} 

당신은 더 나은 투어 요구 사항에 맞게 어떻게 구현을 선택할 수 있습니다. BoxedIterClosure 케이스의 경우 'a 평생 동안은 이동하지 않고 클로저 컨텍스트를 빌릴 수 있습니다.

콜백을 저장하고 호출하는 방법을 잘 설명하는 또 다른 SO 답변을 말씀드립니다.

관련 문제