Ce face Vec
Vec<T> este colecția pe care o vei folosi cel mai des în Rust. Este un tablou care își gestionează singur memoria (pe heap): adaugi elemente cu push, iar vectorul crește cât are nevoie. Elementele stau unul lângă altul, deci accesul după poziție (v[i]) este foarte rapid. Pozițiile încep de la 0.
Vec::new() creează un vector gol și nu alocă nimic până la primul element. Macro-ul vec![1, 2, 3] creează un vector cu valori, iar vec![0; 5] unul cu cinci zerouri. Poți obține un Vec și dintr-un iterator, cu collect(), sau dintr-un tablou, cu Vec::from([..]). Ca orice variabilă Rust, vectorul trebuie declarat cu let mut dacă vrei să-l modifici.
Vectorul este proprietarul elementelor: când vectorul iese din domeniu, elementele sunt eliberate. Dacă îl dai unei funcții prin valoare, el se mută și nu îl mai poți folosi. Funcțiile care doar citesc primesc de obicei &[T] (un slice), iar cele care modifică primesc &mut Vec<T>. Multe metode folosite pe Vec (sort, contains, iter, windows) vin de fapt de la slice-uri și merg și pe tablouri.
Parametri
| Parametru | Descriere |
|---|---|
T |
Tipul elementelor: i32, f64, String, &str, o structură proprie etc. Toate elementele au același tip. |
vec![a, b, c] |
Macro care creează vectorul direct cu elementele date. |
vec![valoare; n] |
Creează n copii ale valorii (tipul trebuie să implementeze Clone). |
Ce returnează
Vec::new() returnează un vector gol, fără memorie alocată. Metodele vectorului au pagini separate.
Exemple
Exemplul 1: Moduri de a crea un vector
Un vector gol are nevoie de tipul scris explicit (Vec<i32>), pentru că nu există elemente din care compilatorul să-l deducă. {:?} afișează tot vectorul.
fn main() {
let goale: Vec<i32> = Vec::new();
let note = vec![9, 7, 10];
let zerouri = vec![0; 5];
let orase = Vec::from(["Iași", "Cluj", "Timișoara"]);
let patrate: Vec<u32> = (1..=5).map(|x| x * x).collect();
println!("goale: {:?} (len = {})", goale, goale.len());
println!("note: {:?}", note);
println!("zerouri: {:?}", zerouri);
println!("orase: {:?}", orase);
println!("patrate: {:?}", patrate);
}
Rezultat
goale: [] (len = 0)
note: [9, 7, 10]
zerouri: [0, 0, 0, 0, 0]
orase: ["Iași", "Cluj", "Timișoara"]
patrate: [1, 4, 9, 16, 25]
Exemplul 2: Adăugare, parcurgere și media notelor
Tipul Vec<i32> este dedus din primul push. for nota in ¬e parcurge vectorul fără să-l consume, așa că îl putem folosi și după buclă.
fn main() {
let mut note = Vec::new();
note.push(8);
note.push(10);
note.push(7);
let mut suma = 0;
for nota in ¬e {
suma += nota;
}
let media = suma as f64 / note.len() as f64;
println!("Ana are {} note: {:?}", note.len(), note);
println!("Media: {:.2}", media);
println!("Prima notă: {}", note[0]);
}
Rezultat
Ana are 3 note: [8, 10, 7]
Media: 8.33
Prima notă: 8
Exemplul 3: Vectorul dat unei funcții: împrumut sau mutare
total doar citește, deci primește &[f64]. adauga_tva modifică, deci primește &mut Vec<f64>. La final, let mutat = cos; mută vectorul: de acum doar mutat poate fi folosit.
fn total(preturi: &[f64]) -> f64 {
preturi.iter().sum()
}
fn adauga_tva(preturi: &mut Vec<f64>) {
for p in preturi.iter_mut() {
*p *= 1.21;
}
}
fn main() {
let mut cos = vec![12.5, 30.0, 7.25];
println!("Total fără TVA: {:.2} lei", total(&cos));
adauga_tva(&mut cos);
let afisare: Vec<String> = cos.iter().map(|p| format!("{p:.2}")).collect();
println!("Prețuri cu TVA: {}", afisare.join(", "));
let mutat = cos; // cos a fost mutat și nu mai poate fi folosit
println!("Total cu TVA: {:.2} lei", total(&mutat));
}
Rezultat
Total fără TVA: 49.75 lei
Prețuri cu TVA: 15.12, 36.30, 8.77
Total cu TVA: 60.20 lei
Greșeli frecvente
- Citești o poziție care nu există, de exemplu
v[3]pe un vector cu 3 elemente. Programul se oprește cupanic: index out of bounds: the len is 3 but the index is 3. Când poziția poate lipsi, foloseștev.get(i), care returneazăOption. - Scrii
let v = Vec::new();și nu adaugi nimic: compilatorul spune type annotations needed for Vec<_>. Scrie tipul:let v: Vec<i32> = Vec::new();. - Folosești vectorul după ce l-ai dat prin valoare unei funcții sau altei variabile: eroarea borrow of moved value. Dă-l prin referință (
&v) sau, dacă chiar ai nevoie de două copii, cuv.clone(). - Parametri de tip
&Vec<T>pentru funcții care doar citesc. Merge, dar&[T]este mai general: acceptă și tablouri, și bucăți de vector (&v[1..3]).
Comenzi înrudite
Vec::push: push adaugă un element la sfârșitul vectorului; pop îl scoate pe ultimul și îl returnează ca Option.Vec::with_capacity: Creează un vector cu loc rezervat dinainte; capacity spune cât loc are, iar reserve mărește locul fără să adauge elemente.Vec::get: Citește elementul de pe o poziție fără risc de panic: returnează Some(&element) sau None dacă poziția nu există.Vec::iter: Cele trei moduri de a parcurge un vector: iter dă referințe, iter_mut dă referințe mutabile, into_iter dă elementele.Vec::len: len returnează numărul de elemente din vector; is_empty spune dacă vectorul nu are niciun element.VecDeque: Coada cu două capete: adaugă și scoate rapid elemente atât la început, cât și la sfârșit.HashMap: Dicționarul din Rust: asociază fiecărei chei o valoare și o găsește foarte repede după cheie. Ordinea nu este garantată.