Ce face slice-uri (&[T] și &str)
Un slice este o referință la o secvență continuă de elemente: &[T] pentru elemente de tip T și &str pentru text. El nu deține datele; ține doar adresa primului element și lungimea. Nu copiază nimic, deci este ieftin de creat și de transmis.
Se creează cu un interval: &v[1..4] conține elementele cu indicii 1, 2 și 3 (capătul din dreapta nu este inclus). &v[..2] înseamnă de la început, &v[2..] până la sfârșit, &v[..] totul. Un interval în afara datelor oprește programul cu panică.
Funcțiile care doar citesc o listă ar trebui să primească &[T], nu &Vec<T>: așa acceptă și array-uri, și vectori, și bucăți din ei. La fel, pentru text primește &str, nu &String. La un &str, capetele intervalului sunt în octeți și trebuie să cadă între caractere: &"Iași"[0..3] dă panică, pentru că ș ocupă octeții 2 și 3.
Exemple
Exemplul 1: Bucăți dintr-un vector
Aceeași funcție suma primește tot vectorul, o parte din el și un array. Niciun element nu este copiat.
fn suma(valori: &[i32]) -> i32 {
valori.iter().sum()
}
fn main() {
let vanzari = vec![120, 80, 95, 200, 150, 60];
println!("Tot anul: {}", suma(&vanzari));
println!("Primele 3 luni: {}", suma(&vanzari[..3]));
println!("Lunile 4-5: {:?}", &vanzari[3..5]);
println!("Un array: {}", suma(&[1, 2, 3]));
let (prima, a_doua) = vanzari.split_at(3);
println!("{prima:?} | {a_doua:?}");
}
Rezultat
Tot anul: 705
Primele 3 luni: 295
Lunile 4-5: [200, 150]
Un array: 6
[120, 80, 95] | [200, 150, 60]
Exemplul 2: Slice-uri de text (&str)
prenume se referă la o parte din nume_complet, fără să creeze un text nou. split_once returnează tot slice-uri. Pozițiile sunt în octeți; find returnează tot o poziție în octeți, deci intervalul cade corect între caractere.
fn initiala(text: &str) -> &str {
let sfarsit = text.chars().next().map_or(0, |c| c.len_utf8());
&text[..sfarsit]
}
fn main() {
let nume_complet = String::from("Ștefan Popescu");
let spatiu = nume_complet.find(' ').unwrap();
let prenume = &nume_complet[..spatiu];
println!("Prenume: {prenume} ({} octeți)", prenume.len());
println!("Inițiala: {}", initiala(&nume_complet));
if let Some((oras, judet)) = "Iași, IS".split_once(", ") {
println!("Oraș: {oras}, județ: {judet}");
}
}
Rezultat
Prenume: Ștefan (7 octeți)
Inițiala: Ș
Oraș: Iași, județ: IS
Exemplul 3: Interval care taie un caracter
Ș ocupă 2 octeți (0 și 1), deci octetul 1 este în mijlocul caracterului. Rust refuză să creeze un text invalid și oprește programul.
fn main() {
let oras = "Ștei";
println!("{}", &oras[0..2]);
println!("{}", &oras[0..1]);
}
Rezultat (programul se oprește cu panică)
Ș
thread 'main' (14470836) panicked at main.rs:4:25:
end byte index 1 is not a char boundary; it is inside 'Ș' (bytes 0..2 of string)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Greșeli frecvente
- Scrii funcții cu parametrul
&Vec<i32>sau&String. Funcționează, dar nu acceptă array-uri sau bucăți;&[i32]și&stracceptă tot. - Crezi că
&v[1..3]include indicele 3. Capătul din dreapta este exclus; pentru a-l include scrie&v[1..=3]. - Tai un text cu poziții calculate ca număr de caractere. Pozițiile unui
&strsunt în octeți; pentru primele N caractere foloseștetext.chars().take(n).collect::<String>()sauchar_indices.
Comenzi înrudite
array ([T; N]): Un șir de lungime fixă, cunoscută la compilare, cu elemente de același tip, păstrat direct pe stivă.borrowing și referințe (& și &mut): O referință (&) împrumută o valoare fără să o ia de la proprietar. Regula: oricâte referințe de citire SAU una singură de modificare.ownership (proprietatea asupra valorilor): Regula de bază a lui Rust: fiecare valoare are un singur proprietar, iar când proprietarul dispare, valoarea este eliberată automat.for … in: Parcurge pe rând fiecare element al unui interval, al unei colecții sau al unui iterator.