2016-02-29 8 views
7

Ich habe in der Rust-Dokumentation keine Regeln gefunden, die erklären würden, wie die Lebensdauer auf Verschlüsse zutrifft. Lassen Sie uns ein einfaches Beispiel:Warum kann Rust bei einfachen Verschlüssen nicht auf die richtige Lebensdauer schließen, oder widersprechen sie einander?

fn foo(s: &str) { 
    let id = |x: &str| x; 
    println!("{}", id(s)); 
} 

fn main() { 
    foo("string"); 
} 

Ich dachte, dass der Verschluss in der foo Funktion wie dem folgenden Code ähnlich funktionieren würde:

fn foo(s: &str) { 
    struct Id; // A helper structure for closure 
    impl Id { 
     fn id(self: Self, x: &str) -> &str { &x } 
    } 
    let id = Id; // Creating a closure 
    println!("{}", id.id(s)); 
} 

Letzteres funktioniert gut, aber der ehemalige nicht kompilieren und produziert eine lange Fehlermeldung über widersprüchliche Anforderungen an die Lebensdauer:

t3.rs:2:24: 2:25 error: cannot infer an appropriate lifetime due to conflicting requirements [E0495] 
t3.rs:2  let id = |x: &str| x; 
          ^
t3.rs:2:24: 2:25 note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the block at 2:23... 
t3.rs:2  let id = |x: &str| x; 
          ^
t3.rs:2:24: 2:25 note: ...so that expression is assignable (expected `&str`, found `&str`) 
t3.rs:2  let id = |x: &str| x; 
          ^
<std macros>:3:11: 3:36 note: but, the lifetime must be valid for the expression at 3:10... 
<std macros>:3 print ! (concat ! ($ fmt , "\n") , $ ($ arg) *)) ; 
         ^~~~~~~~~~~~~~~~~~~~~~~~~ 
<std macros>:2:25: 2:56 note: in this expansion of format_args! 
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std macros>) 
t3.rs:3:5: 3:27 note: in this expansion of println! (defined in <std macros>) 
<std macros>:3:11: 3:36 note: ...so type `(&&str,)` of expression is valid during the expression 
<std macros>:3 print ! (concat ! ($ fmt , "\n") , $ ($ arg) *)) ; 
         ^~~~~~~~~~~~~~~~~~~~~~~~~ 
<std macros>:2:25: 2:56 note: in this expansion of format_args! 
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std macros>) 
t3.rs:3:5: 3:27 note: in this expansion of println! (defined in <std macros>) 
error: aborting due to previous error 

ich frage mich, warum Rust kann nicht die richtige Lebensdauer in einfachen Verschlüsse wie die daraus schließen, dass Ich habe oben geschrieben. Darüber hinaus, warum denkt der Compiler, dass es widersprüchliche Anforderungen für die Lebensdauer gibt.

+0

Entfernen Sie die ': & str' und es funktioniert. Die "& str" bedeutet nicht, was Sie denken, dass es bedeutet. Ich habe jetzt keine Zeit zu erklären, wie ich im Bett sein sollte. –

+1

Eigentlich meinte ich '& str', weil es in einem etwas komplexeren Fall notwendig ist. Auf jeden Fall war meine Frage nicht, wie man dieses triviale Beispiel zum Laufen bringt, aber was sind die Regeln hier? Warum findet der Compiler hier die widersprüchlichen Anforderungen? – svat

+0

@ChrisMorgan: Wenn du etwas Zeit hast, wäre es großartig, wenn du erklären könntest, was vor sich geht. Ich habe das Gefühl, es könnte aufgrund einer abgeleiteten "für <'a>" sein, aber es ist nicht ganz klar ... und der Mangel an Antwort nach 20 Stunden scheint zu bedeuten, dass ich nicht der einzige bin, der unsicher ist, was los ist ^^ –

Antwort

0

Der Abschluss kann aus der Methodensignatur nicht auf die Lebensdauer schließen. Effektiv definieren Sie eine Lebensdauer in der Methodensignatur, sagen wir, es ist implizit 'a, und eine andere Lebensdauer, implizit 'b in der Schließung.

Vergleichen Sie die Lebensdauern und es wird kompiliert.

fn foo<'a>(s: &'a str) { 
    let id = |x: &'a str| x; 
    println!("{}", id(s)) 
} 

fn main() { 
    foo("string"); 
} 
+0

Ich bin Entschuldigung, wenn ich meine Frage schlecht formuliert habe, aber ich war interessiert an den _Rules_ für die lebenslange Schlussfolgerung in closures, nicht, wie man den Code kompilieren kann. Außerdem habe ich eine Version mit einer statischen Zeichenkette ausprobiert: 'id (" string ")', und Rust kann die Lebensdauer noch immer nicht korrekt ableiten und den gleichen Fehler erzeugen. Wenn Rust keine Lebensdauer-Inferenz in Closures unterstützt, habe ich kein Problem, sie explizit zu spezifizieren, aber die Fehlermeldung sagt über _conflicting_requirements_, was ich sehr verwirrend finde. – svat

2

Wenn Sie den Typ eines Parameters oder der Rückgabetyp in einem Verschluss angeben, und diese Art ist eine Referenz, der Compiler falsche Erwartungen an die implizite Lebensdauer Parameter, und es gibt keine Möglichkeit, die Lebensdauer Parameter zu definieren, explizit auf eine Schließung. This is a known issue. Die Problemumgehung besteht darin, den Parametertyp oder den Rückgabetyp wegzulassen und den Compiler auf alles schließen zu lassen.

fn foo(s: &str) { 
    let id = |x| x; 
    println!("{}", id(s)); 
} 

fn main() { 
    foo("string"); 
} 

Wenn Sie immer noch eine Art Hinweis geben müssen, können Sie dies mit einem let innerhalb des Verschlusses Bindung:

fn foo(s: &str) { 
    let id = |x| { let y: &str = x; y }; 
    println!("{}", id(s)); 
} 

fn main() { 
    foo("string"); 
}