2016-02-29 9 views
7

Non ho trovato alcuna regola nella documentazione di Rust che spiegherebbe come l'elisione a vita si applica alle chiusure. Facciamo un semplice esempio:Perché Rust non può dedurre la durata corretta in chiusure semplici, o perché sono in conflitto?

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

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

ho pensato che la chiusura nella funzione foo avrebbe funzionato simile al seguente codice:

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)); 
} 

Quest'ultimo funziona bene, ma il primo non riesce a compilare e produce un messaggio di errore lungo sui requisiti di durata contrastanti:

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 

mi chiedo perché ruggine non può dedurre la durata appropriata nelle chiusure semplici come quello che Ho scritto sopra. Inoltre, perché il compilatore pensa che ci siano in conflitto con i requisiti per tutta la vita.

+0

Rimuovere il ': & str' e funziona. Il '& str' là non significa quello che pensi che significhi. Non ho tempo di spiegare ora, tuttavia, dato che dovrei essere a letto. –

+1

In realtà intendevo "& str", perché è necessario in un caso un po 'più complesso. In ogni caso, la mia domanda non era come ottenere questo semplice esempio per funzionare, ma quali sono le regole qui? Perché il compilatore trova qui i requisiti in conflitto? – svat

+0

@ChrisMorgan: Se avete tempo, sarebbe bello se poteste spiegare cosa sta succedendo. Ho la sensazione che potrebbe essere dovuto a un 'dedotto 'per <'a>' ma non è abbastanza chiaro ... e la mancanza di risposta dopo 20 ore sembra significare che non sono l'unico incerto di cosa sta succedendo ^^ –

risposta

0

La chiusura non può dedurre la durata dalla firma del metodo. In pratica definisci una vita nella firma del metodo diciamo che è implicitamente 'a e un'altra vita, implicitamente 'b nella chiusura.

Abbina le vite e verrà compilato.

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

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

I am scusa se ho formulato la mia domanda male, ma ero interessato alle _rules_ per l'inferenza a vita nelle chiusure, non come ottenere il codice da compilare. Ho anche provato una versione con una stringa statica: 'id (" stringa ")', e Rust non può ancora dedurre la durata in modo corretto e produrre lo stesso errore. Se Rust non supporta l'inferenza a vita nelle chiusure, non ho alcun problema a specificarlo esplicitamente, ma il messaggio di errore dice su _conflicting_requirements_, che trovo molto confuso. – svat

2

Quando si specifica il tipo di un parametro o il tipo restituito in una chiusura, e quel tipo è un riferimento, il compilatore imposta aspettative sbagliate sul parametro durata implicita, e non c'è modo di definire il parametro di vita esplicitamente su una chiusura. This is a known issue. La soluzione alternativa è di omettere il tipo del parametro o il tipo restituito e lasciare che il compilatore deduca tutto.

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

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

Se hai ancora bisogno di dare un tipo di suggerimento, è possibile farlo con un let vincolante all'interno della chiusura:

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

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