2014-07-04 14 views
11

Mam dożywotnią problem, próbuję wdrożyć iterator przekazujących swoje pozycje przez odniesienie, oto kod:Iterator powrocie przedmiotów przez odniesienie, kwestia życia

struct Foo { 
    d: [u8; 42], 
    pos: usize 
} 

impl<'a> Iterator<&'a u8> for Foo { 
    fn next<'a>(&'a mut self) -> Option<&'a u8> { 
     let r = self.d.get(self.pos); 
     if r.is_some() { 
     self.pos += 1; 
     } 
     r 
    } 
} 

fn main() { 
    let mut x = Foo { 
     d: [1; 42], 
     pos: 0 
    }; 

    for i in x { 
     println!("{}", i); 
    } 
} 

Jednak ten kod nie robi” t skompilować poprawnie, mam problem związany z życia parametrów, tutaj jest odpowiedni błąd:

$ rustc test.rs 
test.rs:8:5: 14:6 error: method `next` has an incompatible type for trait: expected concrete lifetime, but found bound lifetime parameter 
test.rs:8  fn next<'a>(&'a mut self) -> Option<&'a u8> { 
test.rs:9   let r = self.d.get(self.pos); 
test.rs:10   if r.is_some() { 
test.rs:11    self.pos += 1; 
test.rs:12   } 
test.rs:13   r 
      ... 
test.rs:8:49: 14:6 note: expected concrete lifetime is the lifetime 'a as defined on the block at 8:48 
test.rs:8  fn next<'a>(&'a mut self) -> Option<&'a u8> { 
test.rs:9   let r = self.d.get(self.pos); 
test.rs:10   if r.is_some() { 
test.rs:11    self.pos += 1; 
test.rs:12   } 
test.rs:13   r 
      ... 
error: aborting due to previous error 

Czy ktoś ma pomysł jak rozwiązać ten problem i nadal powrocie przedmiotów przez odniesienie?

Przynajmniej, co ten komunikat oznacza: oczekiwany czas życia betonu, ale znalazł parametr długości życia związany z granicą?

Odpowiedz

14

Note on the version of Rust used: at the time this question and answer were written, the Iterator trait used generics; it has changed to use associated types and is now defined thus:

pub trait Iterator { 
    type Item; 

    fn next(&mut self) -> Option<Self::Item>; 
    … 
} 

And so the incorrect implementation shown here would be like this:

impl<'a> Iterator for Foo { 
    type Item = &'a u8; 

    fn next<'a>(&'a mut self) -> Option<&'a u8>; 
} 

In practical terms this affects nothing; it is merely that A becomes Self::Item .

Definicja cechy Iterator jest tak:

pub trait Iterator<A> { 
    fn next(&mut self) -> Option<A>; 
    … 
} 

Uwaga uważnie: fn next(&mut self) -> Option<A>.

Oto co trzeba:

impl<'a> Iterator<&'a u8> for Foo { 
    fn next<'a>(&'a mut self) -> Option<&'a u8>; 
} 

Uwaga uważnie: fn next<'a>(&'a mut self) -> Option<&'a u8>.

Istnieje kilka problemów tutaj:

  1. pan wprowadzony nowy parametr ogólny <'a> których nie powinno tam być. Dla wygody i dla podkreślenia tego, co się tutaj wydarzyło, powiem o kodzie 'a zdefiniowanym na bloku impl a) i 'a zdefiniowanym w metodzie ρ₁. Nie są one takie same.

  2. Żywotność &mut self różni się od okresu użytkowania cechy.

  3. Żywotność Typ powrotnej jest inna cechą: gdzie A jest &'ρ₀ u8, typ zwrotny wykorzystuje się w miejscu A&'ρ₁ u8. Oczekiwano konkretnego czasu życia ρ₀, ale zamiast tego znaleziono czas życia ρ₁. (Nie jestem pewien precyzyjnie co „związany” bit oznacza, więc będę milczeć o niej bo mogę się mylić.)

Oto co ten wynosi: nie można połączyć żywotność obiekt, który przeglądasz, do &mut self. Zamiast tego musi być związany z czymś w rodzaju, dla którego wprowadzasz cechę. Aby wykonać przykład, iteracja elementów w plasterku odbywa się przez utworzenie nowego obiektu iteratora połączonego z podstawowym plasterkiem, impl<'a, T> Iterator<&'a T> for Items<'a, T>. Wyrażony w inny sposób sposób, w jaki są zaprojektowane cechy iteracji, nie jest, jeśli tworzysz odniesienia, aby zwrócić coś wewnątrz self, ale raczej zwrócić coś wewnątrz innego obiektu, do którego masz odniesienie.

Dla konkretnego, przypuszczalnie prostym przykładzie, należy albo zatrzymać referencje plonowanie, lub zmienić go tak, że obiekt iterator nie zawiera dane, które są iteracji over-niech to jedynie zawierać odniesienie do niej, na przykład&'a [T] lub nawet coś w rodzaju Items<'a, T>.

+0

Bardzo pomocna odpowiedź. Muszę powiedzieć, że 1 - Mam dużo problemów, aby zrozumieć i poprawnie używać typów/typów typów/typów lifetime/genits określonych w struct i traits oraz tych używanych w metodach, stąd moje złe użycie "wszędzie w tym przykładzie. 2 - Wydaje mi się, że dobrze rozumiem, o co ci chodziło, próbowałem pobrać kod Rust i jego biblioteki, aby znaleźć sposób, w jaki podobny przypadek został obsłużony, a to, co powiedziałeś, wydaje się odpowiadać kilku przypadkom, w których parametr życia jest używany w strukturze z odwołanym atrybutem, jak na przykład iterator dla Splits w libcore/slice.rs. Dzięki za pomoc – user3762625

+0

Czasami przykłady w bibliotece standardowej mogą być trudne do zrozumienia; na przykład 'Items' jest w rzeczywistości czymś wyprodukowanym za pomocą makra, więc musisz zrozumieć podstawy makr Rusta, zanim będziesz mógł je zgadnąć! Bądź zawsze gotów na opuszczenie przez irc: //irc.mozilla.org/#rust, zawsze są ludzie, którzy mogą pomóc. –

+0

Chciałbym zauważyć, że istnieje ważny powód zwracania elementu, którego okres istnienia jest * nie * powiązany z iteratorem: pozwala to na wdrażanie * transformacji * w iteracji, co jest na przykład bardzo trudne w C++. –

Powiązane problemy