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 &strA 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:
| Range | Means |
|---|---|
[..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()); // 2Slices 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
Stringowns,&strborrows.&s[a..b]stops beforeb.[..b],[a..]and[..]leave out an end.- Prefer
&strand&[T]for parameters.