ProgrammingBackend Developer

How do slices work in Rust, what types of slices exist, how is safety ensured, and what happens when trying to access out of bounds?

Pass interviews with Hintsage AI assistant

Answer

A slice in Rust is a dynamic representation of a part of a collection where elements are stored in contiguous memory. A typical example of a slice is &[T] or &mut [T]. Slices do not own the data; they reference an external buffer. All slices have a length stored alongside the reference.

Main types:

  • &[T] — immutable slice
  • &mut [T] — mutable slice
  • For strings: &str (essentially a byte slice, always a valid UTF-8)

Slice safety is ensured at the compiler and runtime level: any attempt to access an element out of slice bounds will cause a panic at runtime, and no undefined behavior like in C/C++ will occur.

Example:

let v = vec![1, 2, 3, 4, 5]; let s: &[i32] = &v[1..4]; // slice, references elements 2, 3, 4 println!("{:?}", s); // [2, 3, 4] // s[3]; // panic! (out of bounds)

Trick Question

Can slices be empty? What is the difference between an empty slice and None?

Answer: Yes, slices can be empty (&[]), which means a reference to a data portion with zero length, but it is not equivalent to None. An empty slice is safe to use, while Option<&[T]> is used to distinguish whether "there is a slice at all".

Example:

let s: &[i32] = &[]; assert!(s.is_empty()); // Option<&[i32]> is used when the slice may not exist at all.

Examples of real errors due to ignorance of topic nuances


Story

In a large logging service, a programmer took a slice by a range calculated dynamically from user data. With incorrect slice calculations (for example, when start > end or if end > len), the code worked in tests but caused a panic in production, crashing the process during peak loads.


Story

In an internal library of concurrent hashing, they used &mut [T] and multiple threads concurrently took different slices of the same array. One thread modified the slice, while another took a different slice from the same memory. The program compiled, but due to incorrect division, undefined behavior could arise through unsafe code (using unsafe) if slices overlapped.


Story

In a system parser for network packets, a slice was created unsafely (raw pointer and from_raw_parts). The developer forgot to check the validity of the input packet length. As a result, an attempt to read out of bounds led to application crashes and a vulnerability (potential OOB access), which could have been avoided by proper use of safe slices.