Lesson 19 / 25

String Slices and Array Slices

&str versus String, &[T] versus Vec<T>.

Borrowed views

A slice is a borrowed view into contiguous data: &str into string data, &[T] into arrays or vectors. Functions that take &str accept both String (via &s) and literals, which is why it is the preferred parameter type. String slicing uses byte indices and must fall on character boundaries, or it panics; use chars() or char_indices() when working with characters.

Slices of strings and arrays, run

I ran this with Rust 1.99.0 (cargo run, edition 2024, standard library only). first_word works on a String and a literal; byte slicing gives "foun"; an array slice holds two elements; the first character of the Devanagari word is one char, and byte 1 is not a character boundary.

fn first_word(s: &str) -> &str {    // &str works for String and literals
    s.split(' ').next().unwrap_or("")
}

fn main() {
    let owned = String::from("fountain pen");
    let literal = "desk lamp";
    println!("{} {}", first_word(&owned), first_word(literal));
    let slice = &owned[0..4];
    println!("slice: {slice}");
    let nums = [10, 20, 30, 40];
    let middle = &nums[1..3];               // array slice
    println!("{middle:?} len {}", middle.len());
    let word = "नमस्ते";
    println!("first char: {:?}", word.chars().next());
    println!("is char boundary at 1: {}", word.is_char_boundary(1));
}

Output:

fountain desk
slice: foun
[20, 30] len 2
first char: Some('न')
is char boundary at 1: false

Accept &str, return String

Taking &str makes functions flexible; returning String gives callers ownership without lifetime annotations.

Quick check: Why is &str preferred over &String as a parameter type?

  • It owns the data
  • It is mutable
  • It is always faster to allocate
  • It accepts both String values and string literals
Answer

It accepts both String values and string literals — More flexible borrowing.