2015-01-08 11 views
13

Ho usato per avere qualcosa di simile:Come si memorizza una chiusura in Rust?

struct Foo { 
    pub foo: |uint| -> uint, 
} 

Ora la sintassi di chiusura è obsoleto. Posso fare qualcosa di simile:

struct Foo<F: FnMut(uint) -> uint> { 
    pub foo: F, 
} 

Ma allora qual è il tipo di un oggetto Foo creo?

let foo: Foo<???> = Foo { foo: |x| x + 1 }; 

potrei anche utilizzare un riferimento:

struct Foo<'a> { 
    pub foo: &'a mut FnMut(uint) -> uint 
} 

Ma penso che sia più lento perché a) il deref puntatore, e b) ora non c'è specializzazione per il tipo di FnMut che in realtà finisce per essere Usato.

risposta

17

Questo è sbagliato: Il diretta equivalente sarebbe Box<FnMut(uint) -> uint>. Questo è effettivamente ciò che intendeva realmente la vecchia sintassi.

Correzione: come sottolineato da dbaupp, non è corretto. Le chiusure vecchio stile che utilizzavano la sintassi || erano riferimenti alle chiusure memorizzate nello stack, rendendole equivalenti a &'a mut FnMut(uint) -> uint. Era proc s che erano allocati su heap e equivalevano a Box<FnOnce(uint) -> uint> (è possibile chiamare una sola volta proc). Le mie scuse per l'errore.

Per quanto riguarda il tipo da utilizzare nel terzo snippet di codice, lo non è uno; i tipi di chiusura sono anonimi e non possono essere nominati direttamente. Invece, devi scrivere:

let foo = Foo { foo: |x| x + 1 }; 

Se si sta scrivendo il codice in un contesto in cui si necessità di specificare che si desidera un Foo, devi scrivere:

let foo: Foo<_> = Foo { foo: |x| x + 1 }; 

Il _ dice al sistema di tipi di dedurre il tipo generico effettivo per te.

La regola generale per cui da utilizzare, in ordine decrescente:

  • parametri generici: struct Foo<F: FnMut(uint) -> uint>. Questo è il più efficiente, ma significa che un'istanza specifica Foo può memorizzare sempre solo una chiusura, poiché ogni chiusura ha un tipo di calcestruzzo diverso.
  • Riferimenti tratti: &'a mut FnMut(uint) -> uint. C'è un puntatore indiretto, ma ora è possibile memorizzare un riferimento a qualsiasi chiusura che abbia una firma di chiamata compatibile.
  • Chiusure in scatola: Box<FnMut(uint) -> uint>. Ciò comporta l'allocazione della chiusura sull'heap, ma non devi preoccuparti della durata. Come con un riferimento, è possibile memorizzare qualsiasi chiusura con una firma compatibile.
+1

"L'equivalente diretto sarebbe Box uint> Questo è effettivamente ciò che intendeva realmente la sintassi precedente." No, l'equivalente diretto è '& mut FnMut (uint) -> uint'.Solo 'proc's aveva un'allocazione (il vecchio' proc' è equivalente a 'Box ...>'). – huon

+0

(Inoltre, si noti che '& FnMut' e' Box huon

+0

@dbaupp: Grazie. Do la colpa all'influenza e al nome scarsamente scelto. : P –

Problemi correlati