BudiBadu Logo
Samplebadu

Rust by Example: Slices and Views

Rust 1.75+

Understand slices, a key primitive for efficient data access. This example shows how to create references to contiguous sequences of elements in a collection, such as string slices (&str) and array slices, avoiding unnecessary data copying.

Code

fn main() {
    // --- String Slices ---
    let s = String::from("Hello world");
    
    // A slice is a reference to a part of a String
    let hello = &s[0..5];
    let world = &s[6..11];
    
    println!("Slice 1: {}", hello);
    println!("Slice 2: {}", world);
    
    // Range syntax shortcuts
    let len = s.len();
    let slice1 = &s[0..2];  // "He"
    let slice2 = &s[..2];   // "He" (same as above)
    let slice3 = &s[3..len]; // "lo world"
    let slice4 = &s[3..];    // "lo world" (same as above)
    let slice5 = &s[..];     // "Hello world" (entire string)
    
    println!("Full slice: {}", slice5);
    
    // --- Array Slices ---
    let a = [1, 2, 3, 4, 5];
    let slice = &a[1..3]; // [2, 3]
    
    println!("Array slice: {:?}", slice);
    
    // Slices as function parameters
    // This allows the function to accept both String and &str
    let word = first_word(&s);
    println!("First word: {}", word);
}

fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

Explanation

A Slice is a data type that does not have ownership. Slices let you reference a contiguous sequence of elements in a collection rather than the whole collection. This is incredibly useful for writing efficient code because it avoids copying data. For example, if you want to process just the first word of a sentence, you don't need to create a new string containing that word; you can just create a slice that points to the existing bytes in memory.

Internally, a slice is represented as a "Fat Pointer". Unlike a regular pointer which is just a memory address, a fat pointer contains two words:

  • Pointer: The memory address of the start of the slice.
  • Length: The number of elements in the slice.
This allows Rust to perform bounds checking at runtime without needing to look up the original collection.

String literals in Rust are actually slices. When you write let s = "Hello";, the variable s is of type &str. It's a slice pointing to that specific point in the binary's read-only memory where the string is stored. This is why string literals are immutable.

Code Breakdown

6
let hello = &s[0..5];. We are creating a slice. Internally, this slice stores two things: a pointer to the byte at index 0 of s, and a length of 5. No data is copied.
34
fn first_word(s: &str). By accepting &str instead of &String, this function becomes much more flexible. It can accept references to heap-allocated Strings and string literals.
37
bytes.iter().enumerate(). This is a common pattern for iterating over a collection when you need both the index and the value. enumerate wraps the iterator and returns a tuple (index, reference_to_value).