& borrows a value. * follows a reference to reach the value behind it. The syntax is small, but it sits right in the middle of Rust’s ownership model.If references feel awkward at first, that is normal. In Rust they are not just pointers with nicer spelling. They are part of the language’s safety model.
& creates a reference#
When you write &x, you borrow x:
let x = 42;
let r = &x;Now:
xhas typei32rhas type&i32
r does not own the value. It just refers to it.
This matters because borrowing avoids moves:
fn print_len(s: &String) {
println!("{}", s.len());
}
let name = String::from("m58");
print_len(&name);
println!("{name}");name is still usable after the function call because the function borrowed it instead of taking ownership.
&mut creates a mutable reference#
If a function needs to modify a value without taking ownership, use &mut:
fn bump(n: &mut i32) {
*n += 1;
}
let mut value = 10;
bump(&mut value);Now the function can change the caller’s value in place.
Rust limits mutable borrowing aggressively:
- you can have many immutable references
&T - or one mutable reference
&mut T - but not both at the same time
That rule prevents data races and aliasing bugs.
* dereferences a reference#
When you have a reference and need the value behind it, use *:
let x = 42;
let r = &x;
assert_eq!(*r, 42);Think of it like this:
&xmeans “borrowx”*rmeans “followrto the thing it points to”
When do you actually need *?#
You need explicit dereferencing when the compiler expects the underlying value and not the reference.
fn add_one(n: &i32) -> i32 {
*n + 1
}n is a reference, so n + 1 does not make sense. *n + 1 does.
You also need * when mutating through a mutable reference:
fn double(n: &mut i32) {
*n *= 2;
}Without *, you would be trying to multiply the reference itself.
Why method calls often do not need *#
Rust applies automatic dereferencing in method calls:
let s = String::from("hello");
let r = &s;
println!("{}", r.len());Even though r is &String, the method call works because Rust dereferences it for you.
That is why beginners often see * in arithmetic or assignment, but not in simple method calls.
References to slices are everywhere#
In real Rust code you will often borrow slices instead of concrete collection types:
fn sum(values: &[i32]) -> i32 {
let mut total = 0;
for value in values {
total += *value;
}
total
}Here values is a borrowed slice, and value inside the loop is a borrowed &i32.
That style is common because it makes functions more flexible. A slice parameter can accept arrays, vectors, and other contiguous collections.
A quick mental model#
If you want something simple to remember:
Tis an owned value&Tis a shared borrow&mut Tis an exclusive mutable borrow*refaccesses the value behind a reference
That mental model is enough for most beginner code.
Summary#
&borrows a value without taking ownership.&mutborrows a value mutably so it can be changed in place.*dereferences a reference when you need the underlying value.- Method calls often hide dereferencing through automatic coercions.
Once & and * make sense, ownership and borrowing become much easier to learn.