Fn, FnMut, FnOnce
Trait delle closure
Fn, FnMut, FnOnce è una lezione Learn Rust Coding gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Learn Rust Coding, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Learn Rust Coding include 4 lezioni in totale.
I trait delle closure
Ogni closure implementa automaticamente uno o più di tre trait, in base al modo in cui usa i valori acquisiti:
Fn— prende in prestito in modo immutabile.FnMut— prende in prestito in modo mutabile.FnOnce— acquisisce la proprietà e può essere chiamata una sola volta.
fn main() {
let x = 5;
let show = || println!("x is {}", x); // implements Fn
show();
show();
}Fn: prestito immutabile
Una closure che legge soltanto i valori catturati implementa Fn. Può essere chiamata molte volte senza modificare nulla.
fn main() {
let greeting = String::from("Hi");
let say = || println!("{}", greeting);
say();
say();
}FnMut: prestito mutabile
Una closure che modifica un valore catturato implementa FnMut. La variabile della closure deve essere mut per poterla chiamare.
fn main() {
let mut count = 0;
let mut increment = || {
count += 1;
println!("count {}", count);
};
increment();
increment();
}FnOnce: prende la proprietà
Una closure che sposta un valore catturato fuori dall'ambiente implementa FnOnce. Può essere chiamata una sola volta.
fn main() {
let name = String::from("Ada");
let consume = move || {
let owned = name;
println!("consumed {}", owned);
};
consume();
}La gerarchia dei trait
I trait formano una gerarchia:
- Ogni
Fnè ancheFnMuteFnOnce. - Ogni
FnMutè ancheFnOnce.
Quindi Fn è il più flessibile e FnOnce il meno flessibile.
fn main() {
let value = 42;
let read = || value; // Fn, so also FnMut and FnOnce
println!("{}", read());
}Passare Fn alle funzioni
Una funzione può accettare una closure specificando quale trait richiede. Utilizzi i generics con un vincolo su un trait.
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
f(x)
}
fn main() {
let double = |n| n * 2;
println!("{}", apply(double, 9));
}Accettare FnMut
Se la funzione deve modificare lo stato catturato, richieda FnMut e contrassegni il parametro come mut.
fn call_twice<F: FnMut()>(mut f: F) {
f();
f();
}
fn main() {
let mut total = 0;
call_twice(|| total += 1);
// note: total is borrowed during the call
}Accettare FnOnce
Quando una funzione chiama la closure una sola volta e può permetterle di consumare dei valori, richieda FnOnce.
fn run_once<F: FnOnce() -> String>(f: F) {
let result = f();
println!("{}", result);
}
fn main() {
let s = String::from("done");
run_once(move || s);
}La parola chiave move
La parola chiave move obbliga una closure a prendere la proprietà delle variabili catturate invece di prenderle in prestito.
È essenziale quando una closure deve sopravvivere all'ambito in cui è stata creata, ad esempio nei thread.
fn main() {
let data = vec![1, 2, 3];
let printer = move || println!("{:?}", data);
printer();
}Come Rust sceglie il trait
Non sceglie manualmente il trait. Il compilatore decide in base al corpo della closure:
- Legge soltanto →
Fn - Modifica →
FnMut - Sposta un valore catturato fuori dalla closure →
FnOnce
fn main() {
let mut log = Vec::new();
let mut record = |x: i32| log.push(x); // FnMut
record(1);
record(2);
println!("{:?}", log);
}Scegliere il vincolo corretto
Come regola generale:
- Accetti
Fnquando deve solo chiamare e leggere. - Accetti
FnMutquando la closure modifica lo stato. - Accetti
FnOncequando è sufficiente chiamarla una volta.
Scelga il vincolo più permissivo compatibile con le esigenze.
fn each<F: Fn(i32)>(items: &[i32], f: F) {
for &i in items {
f(i);
}
}
fn main() {
each(&[1, 2, 3], |n| println!("got {}", n));
}Verifica rapida
Abbini il comportamento di una closure al trait corrispondente.
Riepilogo
I tre trait delle closure:
Fn— prende prestiti immutabili, può essere chiamato ripetutamente.FnMut— prende prestiti mutabili, può modificare lo stato.FnOnce— prende la proprietà, può essere chiamato una volta.
Il compilatore deduce il trait; move forza la cattura tramite proprietà.
fn main() {
let base = 5;
let adder = move |x: i32| x + base; // Fn, captures base by move
println!("{}", adder(10));
}Domande Frequenti
La lezione «Fn, FnMut, FnOnce» è gratuita?
Sì — il testo completo di «Fn, FnMut, FnOnce» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Learn Rust Coding, passa a CoddyKit PRO. Il corso Learn Rust Coding include 4 lezioni in totale.
Cosa imparerò in «Fn, FnMut, FnOnce»?
Trait delle closure Eserciti Learn Rust Coding con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Learn Rust Coding?
Non è richiesta alcuna esperienza precedente. Learn Rust Coding su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Fn, FnMut, FnOnce»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Learn Rust Coding?
Sì. Ogni lezione Learn Rust Coding include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Definizione delle funzioni
- Espressioni e istruzioni
- Closure
- Fn, FnMut, FnOnce