2017-12-06 26 views
3

기본값을 만들고 해당 내부 버퍼를 반복하는 일반 함수를 작성하려고합니다. " 이 모든 것은 인수 나 반환 값이없는 함수 내에서 발생합니다. 나는 수명이 잘못 선언 된 것 같아서 제대로 작동하도록 올바르게 설정하는 데 어려움을 겪고 있습니다.값이 충분히 길지 않아서 컨테이너를 만들고 항목을 추가 한 다음 항목을 반복합니다.

여기에는 DefaultIntoIterator 형질뿐만 아니라 하나의 방법이 필요한 Foo이라는 새로운 형질을 구현하는 예제 유형이 있습니다.

trait Foo<T> { 
    fn add(&mut self, T); 
} 

struct FooBar<T> { 
    buf: Vec<Option<T>>, 
    len: usize, 
} 

impl<T> FooBar<T> { 
    fn new() -> Self { 
     let buf = Vec::new(); 
     let len = 0; 
     Self { buf, len } 
    } 

    fn iter(&self) -> FooBarIter<T> { 
     FooBarIter { foo: self, pos: 0 } 
    } 
} 

impl<T> Foo<T> for FooBar<T> { 
    fn add(&mut self, val: T) { 
     self.buf.push(Some(val)); 
     self.len += 1; 
    } 
} 

impl<T> Default for FooBar<T> { 
    fn default() -> Self { 
     Self::new() 
    } 
} 

impl<'a, T: 'a> IntoIterator for &'a FooBar<T> { 
    type Item = &'a T; 
    type IntoIter = FooBarIter<'a, T>; 

    fn into_iter(self) -> Self::IntoIter { 
     self.iter() 
    } 
} 

FooBar은 소유하고있는 벡터에 값을 추가하기 만하면됩니다. non-consuming 반복만을 허용하기 위해서, 나는 밑에있는 Vec을 빌려서 iteration을 정의했고 반복 중에 "현재"인덱스를 유지하면서 소비자가 빌려 오는 각 요소에 대한 참조를 리턴했다.

struct FooBarIter<'a, T: 'a> { 
    foo: &'a FooBar<T>, 
    pos: usize, 
} 

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

    fn next(&mut self) -> Option<Self::Item> { 
     if self.foo.len <= self.pos { 
      return None; 
     } 

     self.pos += 1; 
     self.foo.buf[self.pos - 1].as_ref() 
    } 
} 

일반 함수는, 디폴트 값을 생성 한 다음 참조 (&str 형의) 그 반복하지만 일부 항목을 추가한다. Rust가 빌려준 값인 FooBar이 충분히 오래 살아 있다고 불평하기 때문에 나는 일생을 잘못 선언 한 것 같습니다. 그러나, 그것은 그것이 기능의 끝까지 살아 간다라고 말한다. 그래서 나는 녹이 실제로 빌려주기를 기대하고있는 길이에 관해서 혼란스러워한다. 여기

fn start<'a, T: 'a>() 
where 
    T: Foo<&'a str> + Default, 
    &'a T: IntoIterator<Item = &'a &'a str>, 
{ 
    let mut f = T::default(); 
    f.add("abcd"); 
    f.add("efgh"); 

    for val in &f { 
     println!("{}", *val); 
    } 

    f.add("ijkl"); 

    for val in &f { 
     println!("{}", *val); 
    } 
} 

fn main() { 
    start::<FooBar<&str>>(); 
} 

은 함수의 끝 "빌린 값이 때까지만 살고있다"때문 &f 충분히 오래 살지 않는다는 내용의 오류입니다.

error[E0597]: `f` does not live long enough 
    --> src/main.rs:70:17 
    | 
70 |  for val in &f { 
    |    ^does not live long enough 
... 
73 | } 
    | - borrowed value only lives until here 
    | 
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 61:1... 
    --> src/main.rs:61:1 
    | 
61 |/fn start<'a, T: 'a>() 
62 | | where 
63 | |  T: Foo<&'a str> + Default, 
64 | |  &'a T: IntoIterator<Item = &'a &'a str>, 
... | 
72 | |  } 
73 | | } 
    | |_^ 

나는 또한 &'a IntoIterator 특성에 대한 서로 다른 수명 매개 변수를 설정하려고했습니다,하지만 난 정말 다른 오류에서 빙빙 돌고 정확한 수명을 설정하는 가까워지고 결국.

FooBar으로 달성하려는 내용을 더 자세히 설명하려면 여기 FooBarVec 인 경우 수행하려는 작업의 예가 있습니다.

fn start() { 
    let mut f = Vec::new(); 
    f.push("abcd"); 
    f.push("efgh"); 

    for val in &f { 
     println!("{}", *val); 
    } 

    f.push("ijkl"); 

    for val in &f { 
     println!("{}", *val); 
    } 
} 

오전 나는 심지어 평생 매개 변수를 알아 내려고 노력과 올바른 궤도에, 아니면 완전히 다른 뭔가?

답변

1

나는 당신이 시도하고있는 것이 현재 불가능하다고 믿습니다. 발신자 가 수명을 제어 할 수 있기 때문에

fn start<'a, T: 'a>() 

이 어떤 이해가되지 않습니다 : start에 전달 될 때 발신자가 수명을 지정하기 때문에 시작하는

, 당신의 오류 메시지입니다. 예를 들어, 호출이 start::<Vec<&'static str>>이지만 함수가 임시 값을 만들었습니까? 이 수명은 반복자 구현과도 관련이 있습니다. 호출자가 지시하는 한 값의 참조가 지속되면 반복 될 수 있습니다.

많은 유사한 경우

, 높은 순위 특성은 내가 얻을 수있는 가장 가까운 조금 다른,는 그러나, 솔루션입니다 경계 :

trait Foo<T> { 
    fn add(&mut self, T); 
} 

impl<T> Foo<T> for Vec<T> { 
    fn add(&mut self, val: T) { 
     self.push(val); 
    } 
} 

fn start<T>() 
where 
    T: Default + Foo<&'static str>, 
    for<'a> &'a T: IntoIterator, 
    for<'a, 'b> &'a <&'b T as IntoIterator>::Item: std::fmt::Display, 
{ 
    let mut f = T::default(); 
    f.add("abcd"); 
    f.add("efgh"); 

    for val in &f { 
     println!("{}", &val); 
    } 

    f.add("ijkl"); 

    for val in &f { 
     println!("{}", &val); 
    } 
} 

fn main() { 
    start::<Vec<&str>>(); 
} 

주요 난제가 T: Default + Foo<&'static str>입니다. 내가 볼 수있는 한, T에 대한 구체적인 유형을 전달할 수있는 방법이 없습니다.이 유형은 함수에 의해 정의 된 HRTB를 사용할 수 있습니다. 이 경우 'static을 사용할 수 있습니다.

error[E0277]: the trait bound `for<'a> std::vec::Vec<&str>: Foo<&'a str>` is not satisfied 
    --> src/main.rs:33:5 
    | 
33 |  start::<Vec<&str>>(); 
    |  ^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a str>` is not implemented for `std::vec::Vec<&str>` 
    | 
    = help: the following implementations were found: 
      <std::vec::Vec<T> as Foo<T>> 
    = note: required by `start` 

이 컴파일러는 HRTB에 의해 지정된 하나 호출 사이트에서 선언 수명을 일치 모르는 : 우리가 for <'a> T: Default + Foo<&'a str>를 사용하려고하는 경우, 우리는 오류가 발생합니다. 나는 믿는다. 그러나 확실하지 않다, 그 generic associated types는 문제를 해결할지도 모른다.

0

HRTB를 사용하여 올바른 방향으로 나를 가리켜 주신 덕분에 Shepmaster에게 감사드립니다. 주제를 읽은 후, 그 기능 자체가 FooBarIterFooBarIter::Item의 수명을 제공하도록 할 수있었습니다. FooBarIter을 이제 빌려서 기능이 끝날 때까지 사용할 수 있습니다. FooBar의 수명은 여전히 ​​발신자가 제공 할 수 있습니다.

마지막으로 컴파일하기 위해 필요한 유일한 변경 사항은 다음과 같습니다.

fn start<'a, T>() 
where 
    T: Foo<&'a str> + Default, 
    for<'b> &'b T: IntoIterator<Item = &'b &'a str>, 
{ 
    let mut f = T::default(); 
    f.add("abcd"); 
    f.add("efgh"); 

    for val in &f { 
     println!("{}", *val); 
    } 

    f.add("ijkl"); 

    for val in &f { 
     println!("{}", *val); 
    } 
}