In Rust, le chiusure sono funzioni anonime che possono "catturare" variabili dall'ambiente esterno. La sintassi:
let add = |a: i32, b: i32| a + b;
In Rust ci sono tre tipi di chiusure (differiscono in base al modo in cui catturano le variabili):
&T), può essere chiamata più volte senza mutare l'ambiente.&mut T), i dati della chiusura possono essere modificati durante la chiamata.T).Rust determina automaticamente il tipo necessario, ma puoi specificarlo esplicitamente.
Esempio di differenze:
let s = String::from("hello"); // FnOnce let consume = move || println!("{}", s); // s non è più accessibile dopo la chiamata
Perché una chiusura con la parola chiave move può non essere FnOnce, ma essere Fn o FnMut?
Risposta: La parola chiave move trasferisce la cattura delle variabili per possesso, ma se i dati all'interno della chiusura non vengono mutati e non vengono distrutti, la chiusura rimane compatibile con Fn/FnMut. Ad esempio:
let s = String::from("abc"); let c = move || println!("String: {}", s); // c: impl Fn() c();
c può essere chiamata più volte: il valore s è stato copiato nella chiusura, ma non è stato distrutto.
Storia
Un nuovo sviluppatore Rust in un progetto con flussi di dati ha cercato di scrivere una chiusura senza move, passandola a un altro thread. Di conseguenza, il compilatore segnalava outlived borrow e ha dovuto affrontare rapidamente le sottigliezze di lifetime e move.
Storia
Hanno introdotto la mutabilità all'interno della chiusura, senza cambiare il tipo in FnMut, il che ha causato "mismatched types" in tutti i punti in cui venivano utilizzati iterator.
Storia
Durante l'elaborazione di un grande array, la chiusura ha preso per move tutta la collezione, trasferendo inconsapevolmente il possesso, il che ha portato a perdere l'accesso ai dati dopo il primo ciclo, causando tentativi di accedere a un valore spostato.