2016-09-06 2 views
7

Ich möchte ein Merkmal für Verschlüsse eines bestimmten Typs implementieren. Hier ist ein minimales Beispiel (playground):Das Implementieren eines Merkmals für Verschlüsse führt zu einem Konflikt zwischen gebundener und konkreter Lebensdauer.

trait Foo { 
    fn foo(&self, x: &u32); 
} 

impl<F> Foo for F 
    where F: Fn(&u32) 
{ 
    fn foo(&self, x: &u32) { 
     self(x) 
    } 
} 

fn main() { 
    let _: &FnOnce(&u32) = &|x| {}; // works 
    let _: &Foo   = &|x| {}; // doesn't work 
} 

Es ist in diesem Fehler führt:

error: type mismatch resolving `for<'r> <[[email protected]<anon>:16:29: 16:35] as std::ops::FnOnce<(&'r u32,)>>::Output ==()`: 
expected bound lifetime parameter , 
    found concrete lifetime [--explain E0271] 
    --> <anon>:16:28 
    |> 
16 |>  let _: &Foo   = &|x| {}; 
    |>       ^^^^^^^ 
note: required because of the requirements on the impl of `Foo` for `[[email protected]<anon>:16:29: 16:35]` 
note: required for the cast to the object type `Foo` 

error: type mismatch: the type `[[email protected]<anon>:16:29: 16:35]` implements the trait `std::ops::Fn<(_,)>`, but the trait `for<'r> std::ops::Fn<(&'r u32,)>` is required (expected concrete lifetime, found bound lifetime parameter) [--explain E0281] 
    --> <anon>:16:28 
    |> 
16 |>  let _: &Foo   = &|x| {}; 
    |>       ^^^^^^^ 
note: required because of the requirements on the impl of `Foo` for `[[email protected]<anon>:16:29: 16:35]` 
note: required for the cast to the object type `Foo` 

Ich habe bereits versucht, um explizit die HRTB auf die where Klausel wie folgt hinzu:

where F: for<'a> Fn(&'a u32) 

Aber es hat nicht geholfen. Ich erklärte auch die Lebensdauer auf dem impl Block stattdessen wie folgt aus:

impl<'a, F> Foo for F 
    where F: Fn(&'a u32) { ... } 

Aber dies führt zu einer Lebensdauer Fehler innerhalb des impl Block. I denke,, dass diese Fehler richtig sind und der Lebensdauerparameter nicht auf dem impl Block deklariert werden kann.

Wie kann ich dieses Beispiel beheben?

Antwort

4

Überprüfen dieser Teil des Fehlers aus:

[...] implements the trait std::ops::Fn<(_,)> , but the trait for<'r> std::ops::Fn<(&'r u32,)> is required

Ich denke, dass im Grunde ist es nicht genug, um Code-Typen zu ermöglichen, richtig abgeleitet werden. Hinzufügen eine explizite Typanmerkung ermöglicht das Beispiel kompiliert werden:

let _: &Foo   = &|x: &u32| {}; 
+1

Hmm, also warum kann der Compiler das nicht ableiten? –

+0

@ChrisEmerson Das interessiert mich auch! Deine und Shepmaster's Antwort hat mir schon geholfen! Das Hinzufügen des expliziten Typs ist in meinem Fall nicht schlecht und funktioniert jetzt. Es ist wirklich schwierig zu entscheiden, welche Antwort zu akzeptieren ist: <... Vielleicht die, die erklären kann, warum die Typinferenz fehlschlägt^_ ^ –

0

Haftungsausschluss: Ich habe keine Ahnung, was ich mache.

Die folgenden Werke:

trait Foo<'a> { 
    fn foo(&self, x: &'a u32); 
} 

impl<'a, F> Foo<'a> for F where F: Fn(&'a u32) { 
    fn foo(&self, x: &'a u32) { 
     self(x) 
    } 
} 
+0

Die Verwendung der Eigenschaft (zB 'let f: & Foo = & | x | {}; f.foo (&3);') wird mit dieser Lösung unmöglich. [Playground] (https://play.rust-lang.org/ "? gist = 563c415937fa42d5311c7a08cdaae54f & version = stable & backtrace = 0). –

+0

Nun, es ist über meiner Leistungsstufe - dachte nur, dass Sie diese Option möglicherweise nicht überprüft haben. – ljedrz

+0

Ja, trotzdem danke :) –

3

Hier ist eine Teilantwort, mit einem interessanten Experiment starten:

trait Foo { 
    fn foo(&self, x: &u32); 
} 

impl<F> Foo for F 
    where F: Fn(&u32) 
{ 
    fn foo(&self, x: &u32) { 
     self(x) 
    } 
} 

fn main() { 
    let f1: &Fn(&u32) = &|_x| {}; 
    let f2: &Foo = &f1; 
    // but this fails: 
    // let f3: &Foo = &|_x| {}; 
    f2.foo(&3); 
} 

(Playground)

Alles, was ich getan habe, ist, Ändern Sie die FnOnce zu Fn für die Konsistenz mit dem Merkmal, und weisen Sie Ihre erste Schließung einer Bindung des Typs &Foo - und dieses eine Arbeit.

Das sagt mir, dass das Merkmal selbst in Ordnung ist - es ist ein Problem, das den Typ des Verschlusses ableitet, wenn das Merkmalobjekt gemacht wird. Zurück zu dem Fehler wird uns gesagt, dass der Abschluss std::ops::Fn<(_,)> implementiert, aber for<'r> std::ops::Fn<(&'r u32,)> erforderlich ist. Dies bedeutet, dass das erste, was Sie versucht haben (Hinzufügen der for<'r>... zum Merkmal) hatte keine Wirkung, weil das Merkmal bereits dies erfordert.

An diesem Punkt stecke ich fest - ich glaube nicht, dass ich die Schlussfolgerungsregeln für Verschlüsse in genügendem Detail verstehe, um entweder zu sehen, warum es einen Unterschied gibt, oder wie es funktioniert. Ich hoffe, dass jemand kommt und das füllt!

Verwandte Themen