Guide

Slices and strings

A slice is a reference to part of a string, array, or Vec. It borrows the data, so it never owns anything.

String vs &str

String owns its text and can grow. &str borrows text that lives somewhere else. A string literal like "hi" is a &str.

let mut owned = String::from("hi");owned.push('!');       // String can growlet lit: &str = "hey"; // a literal is &str

A String has methods that change it. push adds one char, push_str adds a &str, and clear empties it. A &str has none of these.

String slices

&s[a..b] borrows the bytes from a up to, but not including, b.

let s = String::from("hello world");let w = &s[6..11];   // "world"

The numbers are byte positions. For plain English letters, one letter is one byte. A slice borrows s, so you can't change s while the slice is in use.

Range shortcuts

You can leave out either end of the range:

RangeMeans
[..3]from the start up to 3
[3..]from 3 to the end
[..]the whole thing

Array slices

The same ranges work on arrays and Vecs. The result has type &[T], such as &[i32]. &mut a[1..3] gives a mutable slice, a &mut [i32], which can change those items in a.

let v = vec![10, 20, 30, 40];let mid = &v[1..3];        // [20, 30]println!("{}", mid.len()); // 2

Slices as parameters

A function that takes &str works with literals and with &String. A function that takes &[i32] works with arrays and with &Vec<i32>. So slice parameters let one function accept more kinds of input.

fn shout(s: &str) {    println!("{s}!");}shout("hi");shout(&String::from("yo"));

Remember

  • String owns, &str borrows.
  • &s[a..b] stops before b.
  • [..b], [a..] and [..] leave out an end.
  • Prefer &str and &[T] for parameters.