Lo slice in Rust è una rappresentazione dinamica di una parte di una collezione i cui elementi sono disposti in memoria in modo consecutivo. Un esempio tipico di slice è &[T] o &mut [T]. Gli slice non possiedono i dati, ma fanno riferimento a un buffer esterno. Tutti gli slice hanno una lunghezza, archiviata insieme al riferimento.
Tipi principali:
&[T] — slice immutabile&mut [T] — slice mutabile&str (di fatto — slice di byte, sempre UTF-8 valido)La sicurezza degli slice è garantita a livello di compilatore e runtime: qualsiasi tentativo di accedere a un elemento al di fuori dei limiti dello slice provocherà un panic durante l'esecuzione, non si verificherà alcun errore irreparabile in memoria come in C/C++.
Esempio:
let v = vec![1, 2, 3, 4, 5]; let s: &[i32] = &v[1..4]; // slice che fa riferimento agli elementi 2, 3, 4 println!("{:?}", s); // [2, 3, 4] // s[3]; // panic! (uscita dai limiti)
Gli slice possono essere vuoti? Qual è la differenza tra uno slice vuoto e None?
Risposta: Sì, gli slice possono essere vuoti (&[]), ciò significa un riferimento a una parte di dati con lunghezza zero, ma non è equivalente a None. Uno slice vuoto è sicuro da usare, mentre Option<&[T]> serve a distinguere se "c'è davvero uno slice".
Esempio:
let s: &[i32] = &[]; assert!(s.is_empty()); // Option<&[i32]> è usato se lo slice potrebbe non esistere affatto.
Storia
In un grande servizio di logging, uno sviluppatore ha preso uno slice su un intervallo calcolato dinamicamente dai dati dell'utente. Con un calcolo errato dello slice (ad esempio, se start > end o se end > len), il codice ha funzionato nei test, ma in produzione ha provocato un "panic" e ha arrestato il processo durante i picchi di carico.
Storia
In una libreria interna di hash concurrent, hanno utilizzato &mut [T] e parallelamente diversi thread prendevano diversi slice dello stesso array. Un thread modificava lo slice, mentre un altro utilizzava un altro slice sulla stessa memoria. Il programma si compilava, ma a causa di una divisione errata potevano verificarsi UB tramite codice non sicuro (utilizzando unsafe), se gli slice si sovrapponevano comunque.
Storia
In un parser di pacchetti di rete di sistema, è stato creato uno slice in modo non sicuro (puntatore raw e from_raw_parts). Lo sviluppatore ha dimenticato di controllare la correttezza della lunghezza del pacchetto in ingresso. Di conseguenza, un tentativo di lettura oltre i limiti ha portato all'arresto dell'applicazione e a una vulnerabilità (potential OOB access), che poteva essere evitata con l'uso corretto degli slice sicuri.