Borrowing is how you use values without taking ownership, and its rules are what the borrow checker enforces.
A reference lets you use a value without owning it. &s creates a shared reference; a function taking &String (or better, &str) can read the string, and the caller keeps ownership. This is called borrowing.
To modify through a reference, both the binding and the reference must be mutable: let mut s = ...; change(&mut s); with fn change(s: &mut String).
The core rule the borrow checker enforces: at any point, you may have either any number of shared references (&T) or exactly one mutable reference (&mut T) to a value, never both. This rules out data races and iterator-invalidation bugs at compile time: you cannot push to a Vec while holding a reference to one of its elements, because the push might reallocate.
References must also never outlive what they point to. Returning &String to a local variable is rejected, because the local is dropped when the function returns. (Return the owned String instead.)
Borrows last only until their last use, not until the end of the block. This is called non-lexical lifetimes, and it is why code like "take &v[0], print it, then v.push(4)" compiles: the shared borrow ended at the print.
The . operator auto-references and auto-dereferences, so s.len() works whether s is a String, &String or &mut String. For other operations, *r dereferences explicitly, for example *count += 1 through a &mut i32.
Example
fn total_len(words: &[String]) -> usize {
words.iter().map(|w| w.len()).sum()
}
fn shout(s: &mut String) {
s.push('!');
}
fn main() {
let mut words = vec![String::from("hi"), String::from("there")];
let first = &words[0]; // shared borrow
println!("first = {first}"); // last use of `first`
words.push(String::from("again")); // OK: shared borrow has ended
shout(&mut words[1]);
println!("{:?} {}", words, total_len(&words)); // ["hi", "there!", "again"] 13
let mut n = 1;
let r = &mut n;
*r += 1; // explicit dereference
println!("{n}"); // 2
}Remember
&Tborrows for reading,&mut Tfor writing; the owner keeps ownership- Many
&Tor one&mut Tat a time, never both - A borrow lasts until its last use, not until the end of the block
Watch out for
- Holding a reference into a
Vecacross apush; the compiler rejects it because the push may reallocate.