Slices (slice, types [T] en &[T]) zijn in Rust geïntroduceerd voor veilige en efficiënte toegang tot subsets van arrays, vectors en andere sequenties van elementen. Ze stellen gebruikers in staat om allocaties en dubbele gegevenskopieën te vermijden door alleen een "zicht" of venster op een deel van de collectie te bieden. Dit verschilt van arrays, waarbij de grootte vastligt op compile-tijd, evenals van dynamische collecties, die een pointer en lengte opslaan, maar het geheugen bezitten.
Bij het werken met arrays en vectors in talen zonder strikte levensduurcontrole komen vaak out-of-bounds fouten, geheugenlekken en gebruik van ongeldige pointers voor. Het is belangrijk om ervoor te zorgen dat bij het werken met subsets van collecties geen kopieën worden gemaakt en dat de geheugenveiligheid behouden blijft, wat vooral relevant is voor systeemniveau.
In Rust is een slice een "pointer + lengte" naar een deel van de gegevens, die de inhoud niet bezit. Ze worden altijd vergezeld door een levensduur, en de compiler garandeert dat de slice de originele array, Vec of String niet overleeft. Al het werk met slices gebeurt via veilige toegangs-methoden, en elke out-of-bounds-toegang leidt tot een panic tijdens runtime.
Voorbeeldcode:
let arr = [1, 2, 3, 4, 5]; let slice = &arr[1..4]; // [2,3,4] type: &[i32] let mut vec = vec![10, 20, 30]; let mut_slice: &mut [i32] = &mut vec[..2]; mut_slice[0] = 99; assert_eq!(vec, [99, 20, 30]);
Belangrijkste kenmerken:
Is het mogelijk om een slice te creëren die groter is dan de originele array of vector?
Nee. De compiler en runtime garanderen dat een slice alleen kan worden gemaakt binnen de toegestane indexen van de originele gegevens. Proberen om buiten de grenzen te gaan zal een panic veroorzaken.
let arr = [1, 2, 3]; let s = &arr[0..4]; // panic bij uitvoering
Zijn slices zelfstandige eigenaren van geheugen?
Nee. Slices zijn slechts een "venster" op gegevens, ze bezitten geen geheugen. Proberen om een slice vanuit een functie terug te geven, als de bron lokaal is, zal resulteren in een compilatiefout.
fn give_slice() -> &[i32] { let arr = [1,2,3]; &arr[1..] } // fout: arr leeft niet lang genoeg
Wat zijn de verschillen tussen slices en arrays in Rust op het niveau van types en bewerkingen?
Array heeft een vaste lengte, die op compile-tijd bekend is, en is volledig in de stack. Een slice kan elke lengte hebben, dynamisch bepaald worden en slaat altijd een pointer en lengte op.
let a: [u32; 3] = [1,2,3]; // Array met vaste lengte let s: &[u32] = &a[..]; // Slice van willekeurige grootte
Een programmeur heeft een slice geretourneerd vanuit een functie, waar een lokale array is gemaakt. Na het verlaten van de functie werd de originele array verwijderd en werd de slice een "hangende" pointer. Dit resulteerde in een bug en zelfs een crash.
Voordelen:
Nadelen:
Een slice wordt altijd gemaakt via een verwijzing naar externe gegevens, de eigenaar van de gegevens en de slice leven even lang. De compiler garandeert een nauwe verbinding van de levensduur tussen de slice en de bron.
Voordelen:
Nadelen: