2015-11-19 7 views
9

Ich versuche, Wiederholungen in einer iterierbaren Sequenz zu finden. Außerdem möchte ich die Elemente kennen, die in dieser Reihenfolge bis zu diesem Punkt aufgetreten sind.Typenkonflikt "gebundener Lebensdauerparameter" vs. "konkrete Lebensdauer" beim Füllen einer Sammlung von einer Schließung

Ich habe eine HashMap erstellt und versuche, insert darauf aus einem von take_while verwendeten Verschluss zu rufen. Jedoch habe ich es bisher nicht geschafft, es aufgrund von Typkonflikten in Bezug auf konkrete/gebundene Lebensdauern kompilieren zu lassen.

ist hier eine vereinfachte Version meines Codes, die den gleichen Fehler aufweist:

use std::collections::HashSet; 

fn main() { 
    let mut seq = HashSet::new(); 
    let mut insert = |k| seq.insert(k); 
    (1..10).cycle().take_while(insert); 
} 

Hier sind die Fehler, die ich erhalten:

error[E0631]: type mismatch in closure arguments 
--> src/main.rs:6:21 
    | 
5 |  let mut insert = |k| seq.insert(k); 
    |      ----------------- found signature of `fn(_) -> _` 
6 |  (1..10).cycle().take_while(insert); 
    |      ^^^^^^^^^^ expected signature of `for<'r> fn(&'r {integer}) -> _` 

error[E0271]: type mismatch resolving `for<'r> <[[email protected]/main.rs:5:22: 5:39 seq:_] as std::ops::FnOnce<(&'r {integer},)>>::Output == bool` 
--> src/main.rs:6:21 
    | 
6 |  (1..10).cycle().take_while(insert); 
    |      ^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime 

Wie muss ich für sie den Code ändern zu Arbeit?

+0

neugierig, es funktioniert, wenn der Verschluss direkt in den 'take_while' Anruf verschoben wird: http://is.gd/OgVK2i –

+0

@ker, es funktioniert, weil Sie eine subtil andere Sache tun - Sie verwenden eine implizite Dereferenzierung in dem Muster, das die Originalcode nicht. –

Antwort

8

Dies ist in der Tat ein Ausleihfehler in Verkleidung.

Iterator<Item = T>::take_while() akzeptiert eine Schließung der Art FnMut(&T) -> bool - das heißt, jedes Element wird durch Referenz an den Verschluss übergeben. Dies ist ziemlich natürlich, da take_while() in der Lage sein muss, das erfolgreich getestete Element zu liefern, so dass es nicht wertmäßig übergeben werden kann.

Das bedeutet, dass insert Argument Typ sein &_, und so HashSet ‚s generische Parameter wird gefolgert auch als &_ geschlossen wird. Dies bedeutet jedoch, dass Sie versuchen, Verweise auf temporäre Werte, die der cycle()-Iterator liefert, in einer Struktur zu speichern, die viel länger lebt. Dies ist nicht durch Ausleihregeln erlaubt. Leider zeigt Rust genau diese Argumentation nicht, da aus irgendeinem Grund nicht abgeleitet werden kann, dass der numerische Typ i32 ist, und er kann auch nicht den korrekten Lebensdauerparameter für den Abschluss ableiten. Darum geht es bei deinem Fehler.

Stattdessen sollte Ihr Closure das Argument dereferenzieren, bevor es in der Menge gespeichert wird. This works:

use std::collections::HashSet; 

fn main() { 
    let mut seq = HashSet::new(); 
    let mut insert = |&k: &i32| seq.insert(k); 
    (1..10).cycle().take_while(insert); 
} 

Ich hatte auch die volle Art des Arguments hinzuzufügen; Wie ich oben sagte, denke ich, dass die Typinferenz nicht stark genug ist, um daraus abzuleiten.

BTW, können Sie tatsächlich die borrow checker Fehler, wenn Sie den Typ explizit angeben:

use std::collections::HashSet; 

fn main() { 
    let mut seq = HashSet::new(); 
    let mut insert = |k: &i32| seq.insert(k); // no dereference 
    (1..10).cycle().take_while(insert); 
} 

Der obige Code ist äquivalent zu Ihrem ursprünglichen Beispiel mit Ausnahme der expliziten Typanmerkung, und es ergibt sich folgende Fehler:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements 
--> src/main.rs:5:43 
    | 
5 |  let mut insert = |k: &i32| seq.insert(k); 
    |           ^
    | 
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 5:22... 
--> src/main.rs:5:22 
    | 
5 |  let mut insert = |k: &i32| seq.insert(k); 
    |      ^^^^^^^^^^^^^^^^^^^^^^^ 
note: ...so that expression is assignable (expected &i32, found &i32) 
--> src/main.rs:5:43 
    | 
5 |  let mut insert = |k: &i32| seq.insert(k); 
    |           ^
note: but, the lifetime must be valid for the block suffix following statement 1 at 5:5... 
--> src/main.rs:5:5 
    | 
5 |/ let mut insert = |k: &i32| seq.insert(k); 
6 | |  (1..10).cycle().take_while(insert); 
7 | | } 
    | |_^ 
note: ...so that variable is valid at time of its declaration 
--> src/main.rs:5:9 
    | 
5 |  let mut insert = |k: &i32| seq.insert(k); 
    |   ^^^^^^^^^^ 
+2

"Ich musste auch den vollen Typ des Arguments hinzufügen; wie ich oben sagte, denke ich, dass die Typinferenz nicht stark genug ist, um daraus abzuleiten." Ich bin ein paar Mal auf solche Fehler gestoßen. Es ist immer mit Verschlüssen in einer Bindung verbunden. Es scheint einen Unterschied zu geben, wie sie instanziiert werden.Wenn der Typ des Parameters nicht als Referenz angegeben wird, scheint die resultierende abgeleitete Referenz früh mit der Lebensdauer des Bereichs des Abschlusses verbunden zu sein, während die Angabe des Typs als Referenz zu einem Abschluss mit der erwarteten höheren Lebensdauer führt. –

Verwandte Themen