Vec::drain în Rust

Scoate din vector elementele dintr-un interval de poziții și le dă înapoi ca iterator, mutate (fără copiere).

Sintaxă
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
where R: RangeBounds<usize>

Ce face Vec::drain

drain(interval) scoate elementele de pe pozițiile din interval (1..4, ..3, 2.., ..) și le returnează ca iterator. Elementele de după interval se mută la stânga, ca vectorul să rămână continuu. Elementele scoase sunt mutate, nu copiate, deci merge și cu String-uri.

v.drain(..) golește tot vectorul, dar îți dă elementele și păstrează capacitatea: vectorul poate fi refolosit. Este diferența față de into_iter(), care consumă vectorul.

Elementele din interval sunt scoase chiar dacă nu parcurgi tot iteratorul: când iteratorul Drain este eliberat, restul elementelor din interval sunt eliberate și ele. Cât timp iteratorul există, vectorul este împrumutat mutabil și nu poate fi folosit.

Parametri

Parametru Descriere
range Intervalul de poziții: a..b (fără b), a..=b, ..b, a.. sau ... Un capăt mai mare decât lungimea dă panic.

Ce returnează

Un iterator Drain care produce elementele scoase, în ordine.

Exemple

Exemplul 1: Scoaterea unui interval

fn main() {
    let mut v = vec![10, 20, 30, 40, 50, 60];
    let mijloc: Vec<i32> = v.drain(1..4).collect();
    println!("scoase: {:?}", mijloc);
    println!("rămase: {:?}", v);

    let toate: Vec<i32> = v.drain(..).collect();
    println!("drain(..) a dat {:?}, iar v = {:?}", toate, v);
}

Rezultat

scoase: [20, 30, 40]
rămase: [10, 50, 60]
drain(..) a dat [10, 50, 60], iar v = []

Exemplul 2: Procesarea mesajelor în loturi de câte 3

drain(..n) scoate primele n mesaje la fiecare pas; min(3) are grijă ca ultimul lot să poată fi mai mic.

fn main() {
    let mut mesaje: Vec<String> = (1..=7).map(|i| format!("mesaj {i}")).collect();
    let mut lot = 1;
    while !mesaje.is_empty() {
        let n = mesaje.len().min(3);
        let bucata: Vec<String> = mesaje.drain(..n).collect();
        println!("lotul {lot}: {:?}", bucata);
        lot += 1;
    }
}

Rezultat

lotul 1: ["mesaj 1", "mesaj 2", "mesaj 3"]
lotul 2: ["mesaj 4", "mesaj 5", "mesaj 6"]
lotul 3: ["mesaj 7"]

Greșeli frecvente

  • Încerci să citești vectorul în timp ce iteratorul drain încă există: cannot borrow `v` as immutable because it is also borrowed as mutable. Colectează întâi (.collect()) sau termină bucla.
  • Folosești drain(..) când oricum nu mai ai nevoie de vector. into_iter() e mai simplu. drain are sens când vectorul rămâne în uz.
  • Dai un interval care depășește lungimea (v.drain(..10) pe un vector cu 7 elemente): panic. Limitează cu min(v.len()).

Comenzi înrudite

  • Vec::split_off: Taie vectorul în două la o poziție: primele elemente rămân, restul sunt mutate într-un vector nou returnat.
  • Vec::truncate: truncate păstrează doar primele len elemente; clear golește vectorul. Ambele lasă capacitatea neschimbată.
  • Vec::retain: Păstrează în vector doar elementele pentru care funcția dată returnează true; restul sunt șterse, în aceeași ordine.
  • Vec::iter: Cele trei moduri de a parcurge un vector: iter dă referințe, iter_mut dă referințe mutabile, into_iter dă elementele.
  • HashMap::drain: Golește dicționarul și dă toate perechile ca iterator, prin valoare; dicționarul rămâne gol, dar utilizabil.