Ce face todo! și unimplemented!
todo!() marchează cod pe care urmează să-l scrii. Tipul lui este ! (tipul care nu returnează niciodată), deci se potrivește oriunde: ca valoare a unei funcții care returnează u32, într-o ramură de match etc. Așa poți compila și testa restul programului înainte să termini totul. Dacă execuția ajunge la el, programul dă panică cu not yet implemented.
unimplemented!() face același lucru tehnic (panică cu not implemented), dar are alt sens: „această funcționalitate nu este și nu va fi suportată aici”, de exemplu o metodă a unui trait care nu are sens pentru un anumit tip.
Ambele primesc opțional un mesaj formatat. Compilatorul nu avertizează că ai todo! în cod; caută-le cu editorul înainte de o versiune finală.
Exemple
Exemplul 1: Program compilat cu o parte nescrisă
Plata cu cardul și cea cu transfer sunt scrise, plata în rate nu. Programul se compilează și funcționează cât timp nu se ajunge la ramura cu todo!.
enum Plata {
Card,
Transfer,
Rate(u32),
}
fn comision(p: &Plata, suma: f64) -> f64 {
match p {
Plata::Card => suma * 0.015,
Plata::Transfer => 2.5,
Plata::Rate(luni) => todo!("comisionul pentru {luni} rate"),
}
}
fn main() {
let plati = [Plata::Card, Plata::Transfer];
for p in &plati {
println!("Comision: {:.2} lei", comision(p, 400.0));
}
let _ = Plata::Rate(6);
}
Rezultat
Comision: 6.00 lei
Comision: 2.50 lei
Exemplul 2: Ce se întâmplă dacă se ajunge la todo!
Același cod, dar acum se cere comisionul pentru plata în 6 rate. Programul se oprește cu not yet implemented și mesajul nostru.
enum Plata {
Card,
Rate(u32),
}
fn comision(p: &Plata, suma: f64) -> f64 {
match p {
Plata::Card => suma * 0.015,
Plata::Rate(luni) => todo!("comisionul pentru {luni} rate"),
}
}
fn main() {
println!("Card: {:.2} lei", comision(&Plata::Card, 400.0));
println!("Rate: {:.2} lei", comision(&Plata::Rate(6), 400.0));
}
Rezultat (programul se oprește cu panică)
Card: 6.00 lei
thread 'main' (14810905) panicked at main.rs:9:30:
not yet implemented: comisionul pentru 6 rate
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Exemplul 3: unimplemented! pentru o operație nesuportată
Bilet implementează trait-ul Produs, dar un bilet nu are greutate. Metoda există doar ca să satisfacă trait-ul și nu este apelată niciodată pentru bilete.
trait Produs {
fn pret(&self) -> f64;
fn greutate_kg(&self) -> f64;
}
struct Carte;
struct Bilet;
impl Produs for Carte {
fn pret(&self) -> f64 { 45.0 }
fn greutate_kg(&self) -> f64 { 0.4 }
}
impl Produs for Bilet {
fn pret(&self) -> f64 { 80.0 }
fn greutate_kg(&self) -> f64 {
unimplemented!("biletele electronice nu au greutate")
}
}
fn main() {
let carte = Carte;
let bilet = Bilet;
println!("Carte: {} lei, {} kg", carte.pret(), carte.greutate_kg());
println!("Bilet: {} lei", bilet.pret());
}
Rezultat
Carte: 45 lei, 0.4 kg
Bilet: 80 lei
Greșeli frecvente
- Uiți un
todo!într-o ramură rar folosită: totul pare să meargă până când, în producție, cineva ajunge acolo. Caută „todo!” în proiect înainte de livrare. - Folosești
todo!unde ar trebui unResultcu eroare: pentru cazuri neacceptate permanent, returnează o eroare clară sau foloseșteunimplemented!cu un mesaj.
Comenzi înrudite
unreachable!: Marchează un loc din cod la care execuția nu ar trebui să ajungă niciodată; dacă ajunge totuși, dă panică.panic!: Oprește firul de execuție curent cu un mesaj de eroare. Se folosește pentru situații care nu ar trebui să apară niciodată (bug-uri).match: Compară o valoare cu o listă de tipare și execută ramura primului care se potrivește. Compilatorul verifică dacă toate cazurile sunt tratate.trait: Definește un set de metode pe care un tip promite să le aibă. Seamănă cu interfețele din alte limbaje și stă la baza generics.