Le closure sono delle funzioni anonime che possiamo conservare in una variabile o passare come argomenti in altre funzioni. La differenza con le funzioni generiche è che le closure possono catturare la variabile locale e utilizzarla fuori dal suo ambito.
Le closure in Rust possono catturare il riferimento di una variabile, conservarla in variabile mutabile oppure prenderne la proprietà.
Come si scrive una closure in Rust
La funzione anonima di Rust si distingue dalle funzioni generiche perché gli argomenti vanno passate dentro due barre verticali | | chiamate pipe e non dentro le parentesi tonde. Poi si scrivono le istruzioni su cosa fare della variabile catturata.
Nell’esempio sotto la variabile catturata non può essere modificata né spostata ed è riutilizzabile tutte le volte che si vuole.
fn main() {
let multiply = 2;
let multiple = |x: i32| x * multiply;
let x = multiple(2);
let y = multiple(3);
println!("{x}");
println!("{y}");
}
Possiamo fare in modo che la closure modifichi la variabile catturata ma in questo caso dobbiamo lavorare con variabili mutabili.
fn main() {
let mut multiply = 2;
let mut multiple = |x: i32| {
let product = x * multiply;
multiply += 1;
product
};
let x = multiple(2); //multiply diventa 3
let y = multiple(2); //Viene moltiplicato 2 x 3
println!("{x}");
println!("{y}");
}
Quando catturiamo una variabile per spostamento, rimangono valide le regole dell’ownership. Se il tipo della variabile implementa Copy come i numeri, allora viene creata una copia del valore e la variabile originale esiste ancora. Quindi il codice iniziale funziona lo stesso. Ma per i tipi dinamici come le String, la variabile originale non esiste più e il suo valore appartiene alla closure e può essere utilizzato solo tramite la funzione anonima.
fn main() {
let multiply = String::from("2");
let multiple = move |x: i32| x * multiply.parse::<i32>().unwrap();
let x = multiple(2);
let y = multiple(3);
println!("{x}");
println!("{y}");
println!("{}", multiply); //errore
}
Esempio completo:
#[derive(Debug)]
struct User {
id: i32,
username: String,
}
fn main() {
let mut list_user = [
User {
id: 3,
username: "Luke".to_string(),
},
User {
id: 2,
username: "Noah".to_string(),
},
User {
id: 1,
username: "Mark".to_string(),
},
];
list_user.sort_by_key(|user| user.username.clone());
println!("{:?}",list_user);
list_user.sort_by_key(|user| user.id);
println!("{:?}",list_user);
}