2017-01-22 2 views
2

Ich versuche, einen Iterator auf meiner eigenen Struktur zu implementieren. Meine allgemeine Vorgehensweise besteht darin, einen Iterator zu erzeugen und zu speichern, wenn das erste Mal next aufgerufen wird, und dann diesen Iterator jedes Mal aufzurufen, wenn ich einen Wert benötige.Versuch, einen Iterator zu implementieren: kann aufgrund von in Konflikt stehenden Anforderungen keine geeignete Lebensdauer ableiten

Mein minimal Versagen Beispiel looks like this, und das Herz ist:

if !self.vals.is_some() { 
     self.vals = Some(Box::new({ 
      self.display.chars().filter(|&i| i == self.look_for) 
     }) as Box<std::iter::Iterator<Item = _>>); 
    } 

Mein Code zu kompilieren fehlschlägt, die folgende Meldung Herstellung:

help: consider using an explicit lifetime parameter as shown: fn next(self: &'a mut Self) -> Option<<Self>::Item> 

der Beratung Nach hilft nicht (führt nur zu mehr Kompilierungsfehlern, die besagen, dass meine Implementierung mit der Iterator-Traitdefinition nicht kompatibel ist.

Ich würde mich über die Hilfe freuen, die wh es geht schief und wie kann ich es beheben.

Antwort

3

Das Problem ist, dass die Schließung, die Sie an filter weitergeben müssen self, aber you can't store a reference to self in the struct itself ausleihen.

In diesem Fall können wir umgehen, indem Sie stattdessen eine Kopie des Werts im Abschluss speichern. Dies geschieht in zwei Schritten:

  1. Weisen Sie self.look_for einer lokalen Variablen zu und verwenden Sie stattdessen die lokale Variable im Abschluss. Auf diese Weise ist der Verschluss nicht an self gebunden.
  2. Fügen Sie move zum Verschluss hinzu. Die Schließung wird somit die lokale Variable nach Wert erfassen.

Hier ist der endgültige Code:

impl<'a> Iterator for StatefulCounter<'a> { 
    type Item = bool; 
    fn next(&mut self) -> Option<Self::Item> { 
     if !self.vals.is_some() { 
      let look_for = self.look_for; 
      self.vals = Some(Box::new({ 
       self.display.chars().filter(move |&i| i == look_for) 
      })); 
     } 

     if let &Some(v) = &self.vals.as_mut().unwrap().next() { 
      Some(expensive(v)) 
     } else { 
      None 
     } 
    } 
} 

Die explizite Umwandlung auf der Box nicht notwendig ist, so dass ich entfernt es.

+0

'! Self.vals.is_some()' => 'self.vals.is_none()' und einige 'map' auf der letzten Zeile würden es auch schöner machen. – Shepmaster

+0

Das macht langsam Sinn - danke für die ausführliche Antwort! Aber ich habe Mühe, diesen Ansatz zu verallgemeinern: Mein wirkliches Szenario ist eher wie https://play.rust-lang.org/?gist=c43e28b29426cbc50982242f222599f8&version=nightly&backtrace=0, wo ich nicht nur ein Feld packe, sondern * eine anrufe Funktion auf self, die das Feld zurückgibt (ein abgeleiteter Wert). Gibt es einen Ansatz, der in dieser Situation funktioniert? – Bosh

+0

@Bosh: Wenn Sie das "a" in "&" ein self "in" look_for_details "entfernen, wird es kompiliert. –

Verwandte Themen