*Operator
Explanation
* has three unrelated meanings depending on position:
- Binary multiplication (
a * b) — overloadable viastd::ops::Mul. - Prefix dereference (
*ref) — follows a reference or smart pointer to the value it points to. Overloadable viastd::ops::Deref(andDerefMutfor*ref = value), which is exactly the mechanism that letsBox<T>,Rc<T>, etc. be dereferenced with plain*. Most of the time you don't need to write*explicitly, because auto-deref kicks in for method calls (my_box.method()inserts the derefs for you) — explicit*shows up mainly with operators, pattern matching, or assigning through a reference. - Raw pointer type (
*const T,*mut T) — appears only in a type position, never as an expression on its own; dereferencing a raw pointer (*ptr) requires anunsafeblock, unlike dereferencing&T.
Rust's grammar disambiguates these purely by position: * before an
expression with nothing on its left is prefix (dereference); * between
two expressions is binary (multiplication); *const/*mut immediately
followed by a type is the raw pointer type former.
Usage examples
Dereferencing a reference
let x = 5;
let r = &x;
let y = *r; // <- `*` dereferences `r`, reading the value it points to
Sharing data with multiple references
Reading through a smart pointer with explicit * is mostly needed
outside method calls — for comparisons, formatting, or passing the
pointee itself somewhere a reference isn't wanted.
use std::rc::Rc;
let shared_config = Rc::new(String::from("production"));
let handle_a = Rc::clone(&shared_config);
let handle_b = Rc::clone(&shared_config);
if *handle_a == *handle_b { // <- `*` follows each handle to the String it points to
println!("both handles agree: {}", *handle_a); // <- and again here, for formatting
}
Deref lets Rc<T>/Box<T> be read as if they were a
plain &T, and auto-deref already handles method calls (handle_a.len()
needs no *) — explicit * is reserved for the cases auto-deref doesn't
cover, per the Book's Deref chapter.
Mutating through a reference
Writing *reference = value (or a compound form like *reference += value) is how a function mutates the caller's data through a &mut
parameter, rather than rebinding its own local copy of the pointer.
fn apply_offset(reading: &mut f64, offset: f64) {
*reading += offset; // <- `*` dereferences the &mut, writing through it
}
let mut temperature = 21.5;
apply_offset(&mut temperature, -0.3);
println!("calibrated: {temperature}");
Per the Book's references chapter,
writing reading = ... without the * is a type mismatch the compiler
rejects (an f64 can't be assigned to a &mut f64 place — rustc's
E0308 suggests adding the *) — *reading = ... is what makes the
write go through the reference to the value itself.