References and Borrowing
How to use a value without taking ownership of it. Shared and mutable references, the borrowing rules, and the errors you hit when you break them.
Moving a value into a function every time you want to read it gets old fast. You pass a String to calculate_length, and now you can't use it anymore unless the function hands it back. References fix this. A reference lets a function borrow a value: it can use it, but the caller still owns it.
The problem references solve
fn calculate_length(s: String) -> usize {
s.len()
} // s is dropped here
fn main() {
let name = String::from("ferris");
let len = calculate_length(name);
// println!("{name}"); // error: name was moved
println!("{len}");
}
name moved into the function and was dropped at the end of it. To keep using it, you would have to return it as part of a tuple. That works, but it's noise.
Shared references: &T
Put & in front of the value and in front of the parameter type:
fn calculate_length(s: &String) -> usize {
s.len()
} // s goes out of scope, but it doesn't own the String, so nothing is dropped
fn main() {
let name = String::from("ferris");
let len = calculate_length(&name);
println!("{name} has {len} letters");
}
&name creates a reference that points at name without owning it. Creating a reference is called borrowing. When the function returns, the borrow ends and name is still fully usable.
A shared reference is read-only. This does not compile:
fn add_suffix(s: &String) {
s.push_str("!"); // error[E0596]: cannot borrow `*s` as mutable
}
Prefer &str over &String:
For function parameters, &str is usually better than &String. A &String coerces to &str automatically, and &str also accepts string literals and slices. The same goes for &[T] instead of &Vec<T>.
Mutable references: &mut T
If the function needs to change the value, borrow it mutably. The variable itself must be declared mut:
fn add_suffix(s: &mut String) {
s.push_str("!");
}
fn main() {
let mut greeting = String::from("hello");
add_suffix(&mut greeting);
println!("{greeting}"); // hello!
}
The two borrowing rules
At any point in time you can have either:
- any number of shared references (
&T), or - exactly one mutable reference (
&mut T).
Not both. And every reference must always point to a valid value.
That's the whole rule set. It's what stops data races at compile time: two pieces of code can't change the same data at once, and nobody can read data while someone else is changing it.
fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s; // error[E0499]: cannot borrow `s` as mutable more than once at a time
println!("{r1}, {r2}");
}
Mixing shared and mutable borrows fails the same way:
fn main() {
let mut s = String::from("hello");
let r1 = &s;
let r2 = &mut s; // error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
println!("{r1}, {r2}");
}
Borrows end at their last use
A borrow doesn't last until the end of the block. It lasts until the reference is used for the last time. This is called non-lexical lifetimes (NLL), and it makes most real code just work:
fn main() {
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{r1} and {r2}"); // last use of r1 and r2
let r3 = &mut s; // fine: the shared borrows are already over
r3.push_str(" world");
println!("{r3}");
}
If you hit E0502, look for a shared reference that is still used after the mutable borrow. Moving that use earlier, or cloning the small piece you need, usually fixes it.
Dangling references are not allowed
A reference can't outlive the value it points to. Returning a reference to a local variable fails:
fn dangle() -> &String { // error[E0106]: missing lifetime specifier
let s = String::from("hello");
&s
} // s is dropped here, so the reference would point at freed memory
The fix is to return the owned value instead:
fn no_dangle() -> String {
String::from("hello")
}
Quick reference
| You want to | Use | Caller writes |
|---|---|---|
| Read a value without taking it | &T | f(&x) |
| Change a value without taking it | &mut T | f(&mut x) (and let mut x) |
| Take the value for good | T | f(x) |
Common errors
- E0382 borrow of moved value: you passed
xinstead of&x. - E0596 cannot borrow as mutable: the variable isn't
mut, or the parameter is&Tinstead of&mut T. - E0499 / E0502: two borrows overlap. Shorten one of them.
- E0106 missing lifetime specifier: you're returning a reference to something local. Return an owned value.
Next, The Slice Type shows a special kind of reference that points at part of a collection.