2015-01-07 10 views
9

qualcuno può aiutarmi a riscrivere questo pezzo di codice con nuove chiusure disimballati:Come riscrivere il codice per nuove chiusure disimballati

struct Builder; 
pub fn build(rules: |params: &mut Builder|) -> Builder { 
    let mut builder = Builder::new(); 
    rules(&mut builder); 

    builder 
} 

Ho provato a scrivere in questo modo, ma ho avuto un errore di vita:

pub fn build<F>(rules: F) -> Builder where F: FnOnce<(&mut Builder,),()> { 
    let mut builder = Builder::new(); 
    rules(&mut builder); 

    builder 
} 

valico/src/builder.rs:48:59: 48:71 error: missing lifetime specifier [E0106] 
valico/src/builder.rs:48  pub fn build<F>(rules: F) -> Builder where F: FnOnce<(&mut Builder,),()> { 
                        ^~~~~~~~~~~~ 

Quale ciclo di vita devo specificare? Simplified example in the sandbox.

+1

Close-elettore: perché questo è offtopic? – huon

risposta

12

Ciò richiede higher rank trait bounds, in particolare, le durate di rango superiore. La sintassi completa su unsugared sarebbe F: for<'a> FnOnce<(&'a mut Builder,),()>.

L'utilizzo di una durata della funzione non può funzionare, ad es. se avessimo

pub fn build<'b, F>(rules: F) -> Builder where F: FnOnce<(&'b mut Builder,),()> 

Questo dice che build lavori con qualunque durata del chiamante desidera (ad esempio, potrebbero scelto 'b == 'static), ma questo non è valido, perché non v'è una vita concreta specifica che deve essere utilizzato il : la durata del &mut builder all'interno della funzione. L'utilizzo di F: for<'a> ... in un limite dice che F funziona con qualsiasi durata 'a, quindi il compilatore vede che è legale sostituire in quello di &mut builder.

Come ho accennato sopra, questa è la sintassi unsugared davvero brutta. Ci sono due modi in cui questo può essere reso molto più bello. In primo luogo, il modo canonico per utilizzare i tratti di chiusura è lo zucchero (): for<'a> FnOnce(&'a mut Builder) ->() oppure, come nel resto di Rust, è possibile eliminare lo ->(): for<'a> FnOnce(&'a mut Builder). (. NB: questo è solo zucchero per FnOnce<...>, ma solo la sintassi zuccherata sarà stabilizzata per l'interazione con questi tratti a 1,0.)

Poi, la sintassi paren ha una piccola regola in più: inserisce automaticamente vite che agiscono come for<'a> (in particolare, viene sottoposto a lifetime elision con una durata inserita inserita in un valore for sul tratto), quindi solo F: FnOnce(&mut Builder) equivale a F: for<'a> FnOnce(&'a mut Builder) ed è la versione consigliata.

L'applicazione di queste correzioni al tuo esempio box:

pub fn initialize_with_closure<F>(rules: F) -> uint where F: FnOnce(&mut uint) { 
    let mut i = 0; 
    rules(&mut i); 

    i 
} 

// equivalently 
pub fn initialize_with_closure_explicit<F>(rules: F) -> uint where F: for<'a> FnOnce(&'a mut uint) ->() { 
    let mut i = 0; 
    rules(&mut i); 

    i 
} 

pub fn main() { 
    initialize_with_closure(|i: &mut uint| *i = *i + 20); 
    initialize_with_closure_explicit(|i: &mut uint| *i = *i + 20); 
} 

playpen

Problemi correlati