Slice (fragment) w Rust to dynamiczna reprezentacja części kolekcji, której elementy są uporządkowane w pamięci sekwencyjnie. Typowym przykładem slice'a jest &[T] lub &mut [T]. Slice'y nie posiadają danych, a odnoszą się do zewnętrznego bufora. Wszystkie slice mają długość, która jest przechowywana razem z odniesieniem.
Główne typy:
&[T] — niemodyfikowalny slice&mut [T] — modyfikowalny slice&str (faktycznie — slice bajtów, zawsze poprawny UTF-8)Bezpieczeństwo slice'a jest zapewniane na poziomie kompilatora i runtime'u: wszelkie próby odwołania się do elementu poza granicami slice'a spowodują panikę (panic) w czasie wykonania, żaden niezdobny błąd w pamięci jak w C/C++ się nie wydarzy.
Przykład:
let v = vec![1, 2, 3, 4, 5]; let s: &[i32] = &v[1..4]; // slice, odnosi się do elementów 2, 3, 4 println!("{:?}", s); // [2, 3, 4] // s[3]; // panic! (wyjście poza granice)
Czy slice'y mogą być puste? Czym różni się pusty slice od None?
Odpowiedź: Tak, slice mogą być puste (&[]), co oznacza odniesienie do części danych o zerowej długości, ale nie jest analogiczne do None. Pusty slice jest bezpieczny w użyciu, a Option<&[T]> służy do rozróżnienia "czy slice w ogóle istnieje".
Przykład:
let s: &[i32] = &[]; assert!(s.is_empty()); // Option<&[i32]> jest używane, jeśli slice może w ogóle nie istnieć.
Historia
W dużej usłudze logowania programista wziął slice według zakresu obliczanego dynamicznie z danych użytkownika. Przy błędnym obliczeniu slice'a (np. przy start > end lub jeśli end > len), kod działał w testach, ale w produkcji spowodował "panic" i awaryjnie zatrzymał proces podczas szczytu obciążenia.
Historia
W wewnętrznej bibliotece równoległego haszowania używano &mut [T] i równolegle kilka wątków brało różne slice tego samego tablicy. Jeden wątek zmieniał slice, a inny na tę samą pamięć brał inny slice. Program się kompilował, ale z powodu niewłaściwego podziału mogły wystąpić UB przez niebezpieczny kod (użycie unsafe), jeśli slice'y jednak się pokrywały.
Historia
W systemowym parserze pakietów sieciowych tworzono slice w sposób niebezpieczny (wskaźnik surowy i from_raw_parts). Programista zapomniał sprawdzić poprawność długości przychodzącego pakietu. W rezultacie próba odczytu poza granice spowodowała awarię aplikacji i podatność (potencjalny dostęp poza granicami), którą można było usunąć dzięki właściwemu zastosowaniu bezpiecznych slice'ów.