Iterator::cloned în Rust

Transformă un iterator de referințe (&T) într-unul de valori (T): copied copiază tipuri simple, cloned clonează orice tip Clone.

Sintaxă
fn cloned<'a, T>(self) -> Cloned<Self>
where Self: Iterator<Item = &'a T>, T: Clone + 'a

fn copied<'a, T>(self) -> Copied<Self>   // Rust 1.36
where Self: Iterator<Item = &'a T>, T: Copy + 'a

Ce face Iterator::cloned

v.iter() produce referințe. Când ai nevoie de valori proprii (de exemplu ca să colectezi un Vec<i32>, nu Vec<&i32>), adaugă .copied() sau .cloned().

copied() merge doar pentru tipuri Copy (numere, char, bool, &str) și e o copiere ieftină de biți. cloned() merge pentru orice tip Clone, inclusiv String și Vec, dar poate aloca memorie. Preferă copied când merge: îți arată clar că e ieftin.

Există și pe Option: v.iter().max().copied() transformă Option<&i32> în Option<i32>. Ca toate adaptoarele, este leneș: nu face nimic până când iteratorul nu este consumat (de for, collect, sum, count etc.).

Ce returnează

Un iterator Copied sau Cloned care produce T.

Exemple

Exemplul 1: Din &i32 în i32

fn main() {
    let note = vec![7, 9, 10, 6];
    let referinte: Vec<&i32> = note.iter().collect();
    let valori: Vec<i32> = note.iter().copied().collect();
    println!("{:?} {:?}", referinte, valori);

    let maxim: Option<i32> = note.iter().max().copied();
    println!("maxim: {:?}", maxim);
}

Rezultat

[7, 9, 10, 6] [7, 9, 10, 6]
maxim: Some(10)

Exemplul 2: cloned pentru String-uri

String nu este Copy, deci copied() nu compilează; cloned() face câte o copie a fiecărui text.

fn main() {
    let elevi = vec![String::from("Ana"), String::from("Mihai"), String::from("Ioana")];
    let mut sortati: Vec<String> = elevi.iter().cloned().collect();
    sortati.sort();
    println!("originalul: {:?}", elevi);
    println!("copia sortată: {:?}", sortati);
}

Rezultat

originalul: ["Ana", "Mihai", "Ioana"]
copia sortată: ["Ana", "Ioana", "Mihai"]

Greșeli frecvente

  • Folosești copied() pe referințe la String: the trait bound `String: Copy` is not satisfied. Folosește cloned().
  • Clonezi la începutul unui lanț lung, înainte de filter: clonezi și elementele pe care apoi le arunci. Pune cloned() cât mai la final.

Comenzi înrudite

  • Iterator::map: Transformă fiecare valoare a iteratorului cu o funcție și dă un iterator cu rezultatele; nu calculează nimic până la consumare.
  • Iterator::collect: Consumă iteratorul și adună valorile într-o colecție: Vec, String, HashMap, HashSet, chiar Result sau Option.
  • Vec::to_vec: Creează un Vec nou, cu copii ale elementelor dintr-un slice: dintr-un tablou, dintr-o bucată de vector sau dintr-un &[T].
  • Vec::iter: Cele trei moduri de a parcurge un vector: iter dă referințe, iter_mut dă referințe mutabile, into_iter dă elementele.