Rust References and Slices
Learn how to borrow data in Rust using immutable and mutable references, understand the aliasing XOR mutability rule, and work with slices.
Sixth post in the basic Rust series. Ownership ensures memory safety, but moving values everywhere quickly becomes tedious. Borrowing lets you access data without taking ownership.
Borrowing with references#
A reference allows you to refer to a value without taking ownership of it. References are created using the & operator:
fn calculate_length(s: &String) -> usize {
s.len()
}
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{s1}' is {len}.");
}rustBecause calculate_length takes a reference &String, s1 is borrowed rather than moved. s1 remains valid after the function call.
Mutable references#
By default, references are immutable. To modify borrowed data, use a mutable reference &mut:
fn change(s: &mut String) {
s.push_str(", world");
}
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{s}");
}rustTo create a mutable reference, the underlying variable must also be declared with mut.
The fundamental rule of borrowing#
Rust enforces a strict rule to prevent data races at compile time:
You can have either any number of immutable references (
&T) or exactly one mutable reference (&mut T) to a value at a time, but not both.
let mut s = String::from("hello");
let r1 = &s; // OK
let r2 = &s; // OK
// let r3 = &mut s; // ERROR: cannot borrow `s` as mutable because it is also borrowed as immutable
println!("{r1} and {r2}");rustThis “aliasing XOR mutability” rule guarantees that data cannot change unexpectedly while another part of the program is reading it.
Slices#
A slice is a reference to a contiguous sequence of elements in a collection, rather than the whole collection.
String slices#
A string slice (&str) references a portion of a String:
let s = String::from("hello world");
let hello: &str = &s[0..5];
let world: &str = &s[6..11];rustString literals ("hello") are actually string slices pointing directly to compiled binary data.
Array slices#
Slices work on arrays and vectors as well:
let a = [1, 2, 3, 4, 5];
let slice: &[i32] = &a[1..3];
assert_eq!(slice, &[2, 3]);rustConclusion#
Borrowing with references (& and &mut) lets you share data safely. Slices (&str and &[T]) offer flexible, view-only access to sequences. Next in this series: structs.