6.6 Slices: Borrowing Portions of Data

Slices let you reference a contiguous portion of data (like a substring or sub-array) without taking ownership or allocating new memory. Internally, a slice is just a pointer to the data plus a length, giving efficient access while enforcing bounds safety.

6.6.1 String Slices

#![allow(unused)]
fn main() {
let s = String::from("hello world");
let hello = &s[0..5];    // "hello"
let world = &s[6..11];   // "world"
}

A string slice (&str) references part of a String but does not own the data.

6.6.2 Array Slices

#![allow(unused)]
fn main() {
let arr = [1, 2, 3, 4, 5];
let slice = &arr[1..4]; // [2, 3, 4]
}

Vectors (dynamically sized arrays in the standard library) are similar to String and support slicing as well.

Because Rust enforces slice bounds at runtime, it prevents out-of-bounds errors.

6.6.3 Slices in Functions

Functions often receive slices (&[T] or &str) to avoid taking ownership:

fn sum(slice: &[i32]) -> i32 {
    slice.iter().sum()
}

fn main() {
    let arr = [1, 2, 3, 4, 5];

    let partial_result = sum(&arr[1..4]);
    println!("Sum of slice is {}", partial_result);

    let total_result = sum(&arr);
    println!("Sum of entire array is {}", total_result);
}

6.6.4 Comparison with C

In C, slicing typically involves pointer arithmetic:

#include <stdio.h>

void sum(int *slice, int length) {
    int total = 0;
    for(int i = 0; i < length; i++) {
        total += slice[i];
    }
    printf("Sum is %d\n", total);
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    sum(&arr[1], 3); // sum of elements 2, 3, 4
    return 0;
}

C does not perform bounds checking, making out-of-bounds errors a common problem.