Ce face Clone
În Rust, atribuirea let b = a; mută valoarea: după ea, a nu mai poate fi folosit (pentru tipuri ca String, Vec). Dacă ai nevoie de două valori independente, ceri explicit o copie cu a.clone(). Copia este completă („deep copy”): un Vec<String> clonat are propriile texte.
Cel mai simplu obții Clone cu #[derive(Clone)], care clonează câmp cu câmp; merge doar dacă toate câmpurile sunt Clone. Implementarea manuală (impl Clone for Tip, cu metoda clone) îți permite să schimbi ceva la copiere. Excepție de știut: Rc::clone și Arc::clone nu copiază datele, ci doar măresc numărul de proprietari.
clone() poate costa mult (alocă memorie), de aceea Rust nu o face niciodată automat. Înainte de a o adăuga ca să scapi de o eroare de împrumut, verifică dacă nu ajunge o referință (&a).
Parametri
| Parametru | Descriere |
|---|---|
clone(&self) |
Singura metodă obligatorie. Mai există clone_from(&mut self, sursa), care poate refolosi memoria destinației. |
Ce returnează
clone() returnează o valoare nouă, de același tip, independentă de original.
Exemple
Exemplul 1: #[derive(Clone)] și mutarea
#[derive(Clone)]
struct Elev {
nume: String,
note: Vec<u8>,
}
fn main() {
let ana = Elev { nume: String::from("Ana"), note: vec![9, 10] };
let mut copie = ana.clone(); // copie completă
copie.nume.push_str(" (copie)");
copie.note.push(7);
println!("{}: {:?}", ana.nume, ana.note);
println!("{}: {:?}", copie.nume, copie.note);
let mutat = ana; // fără clone: ana este mutată
println!("mutat: {}", mutat.nume);
}
Rezultat
Ana: [9, 10]
Ana (copie): [9, 10, 7]
mutat: Ana
Exemplul 2: Implementare manuală
Copia unui document primește automat sufixul „(copie)” și o versiune resetată, lucru pe care derive nu l-ar face.
struct Document {
titlu: String,
versiune: u32,
}
impl Clone for Document {
fn clone(&self) -> Self {
Document {
titlu: format!("{} (copie)", self.titlu),
versiune: 1,
}
}
}
fn main() {
let original = Document { titlu: String::from("Contract Iași"), versiune: 7 };
let copie = original.clone();
println!("{} v{}", original.titlu, original.versiune);
println!("{} v{}", copie.titlu, copie.versiune);
}
Rezultat
Contract Iași v7
Contract Iași (copie) v1
Greșeli frecvente
- Pui
.clone()peste tot ca să treci de verificarea împrumuturilor. Codul compilează, dar copiază inutil; de multe ori o referință rezolvă problema. - Folosești
#[derive(Clone)]pe o structură cu un câmp care nu eClone(de exemplu un tip propriu fără derive):the trait `Clone` is not implemented. Adaugăderive(Clone)și pe acel tip.
Comenzi înrudite
Copy: Trait marker pentru tipurile copiate automat bit cu bit la atribuire, în loc să fie mutate (numere, char, bool…).fmt::Debug: Trait-ul pentru afișarea de depanare cu {:?} și {:#?}; se obține aproape mereu cu #[derive(Debug)].Default: Trait-ul pentru valoarea implicită a unui tip: Tip::default(), derive(Default) și ..Default::default().Deref: Trait-ul din spatele operatorului * și al conversiei automate &Box<T> -> &T, &String -> &str (deref coercion).