Rust references cheat sheet

A compact guide to where &, &mut, Box, and Option go in Rust type declarations.

The most basic forms

Plain value

let x: i32 = 5;

x owns an i32.

Shared reference

let x: i32 = 5;
let r: &i32 = &x;

r is a shared reference to x.

Mutable reference

let mut x: i32 = 5;
let r: &mut i32 = &mut x;

r is a mutable reference to x.


Option forms

Optional value

let x: Option<i32> = Some(5);
let y: Option<i32> = None;

The Option owns the i32 when it is Some.

Reference to an Option

let x: Option<i32> = Some(5);
let r: &Option<i32> = &x;

You definitely have a reference, and it points to an Option that may be Some or None.

Option containing a reference

let x: i32 = 5;
let r: Option<&i32> = Some(&x);
let n: Option<&i32> = None;

The optional part is the reference itself.

Mutable versions

let mut x: i32 = 5;
let r: Option<&mut i32> = Some(&mut x);

Box forms

Boxed value

let b: Box<i32> = Box::new(5);

b owns a heap-allocated i32.

Reference to a box

let b: Box<i32> = Box::new(5);
let r: &Box<i32> = &b;

This is a reference to the box itself.

Box containing an Option

let b: Box<Option<i32>> = Box::new(Some(5));

Option containing a Box

let x: Option<Box<i32>> = Some(Box::new(5));

These are different:

  • Box<Option<i32>> means the heap allocation always exists, and inside it is either Some or None
  • Option<Box<i32>> means the box itself may or may not exist

Common nested combinations

Reference to an Option of a value

let x: Option<i32> = Some(5);
let r: &Option<i32> = &x;

Option of a reference to a value

let x: i32 = 5;
let r: Option<&i32> = Some(&x);

Reference to an Option of a Box

let x: Option<Box<i32>> = Some(Box::new(5));
let r: &Option<Box<i32>> = &x;

Option of a reference to a Box

let x: Box<i32> = Box::new(5);
let r: Option<&Box<i32>> = Some(&x);

Option of a reference to the boxed value

let x: Box<i32> = Box::new(5);
let r: Option<&i32> = Some(&*x);

Reference to an Option of a reference

let x: i32 = 5;
let y: Option<&i32> = Some(&x);
let r: &Option<&i32> = &y;

Linked-list style declaration

This is very common in Rust:

type List<T> = Option<Box<Node<T>>>;

Read it inside out:

  • a List<T> is
  • an Option
  • of a Box
  • of a Node<T>

So a list is either:

  • None for the empty list, or
  • Some(Box<Node<T>>) for a node on the heap

Example node type:

type List<T> = Option<Box<Node<T>>>;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Node<T> {
    pub val: T,
    pub next: List<T>,
}

A reference to the whole list:

let head: List<i32> = None;
let r: &List<i32> = &head;

A borrowed view into the node inside:

let head: List<i32> = Some(Box::new(Node { val: 1, next: None }));
let node_ref: Option<&Node<i32>> = head.as_deref();

Useful conversion helpers

as_ref()

Turns &Option<T> or Option<T> borrowing context into Option<&T>.

let x: Option<i32> = Some(5);
let r: &Option<i32> = &x;
let y: Option<&i32> = r.as_ref();

as_mut()

let mut x: Option<i32> = Some(5);
let y: Option<&mut i32> = x.as_mut();

as_deref()

Very handy for Option<Box<T>>.

let x: Option<Box<i32>> = Some(Box::new(5));
let y: Option<&i32> = x.as_deref();

It dereferences the Box for you while borrowing.

as_deref_mut()

let mut x: Option<Box<i32>> = Some(Box::new(5));
let y: Option<&mut i32> = x.as_deref_mut();

Pattern matching examples

Matching a borrowed Option

let x: Option<i32> = Some(5);
let r: &Option<i32> = &x;

match r {
    Some(n) => println!("{n}"),
    None => println!("none"),
}

Here n is &i32, because you matched through a shared reference.

Matching an Option<&T>

let x: i32 = 5;
let r: Option<&i32> = Some(&x);

match r {
    Some(n) => println!("{n}"),
    None => println!("none"),
}

Here too, n is &i32.

Matching mutable references

let mut x = Some(5);

if let Some(n) = x.as_mut() {
    *n += 1;
}

Quick mental rules

Rule 1: & always applies to the thing immediately to its right

&Option<i32>

means “reference to Option<i32>”.

Option<&i32>

means “optional reference to i32”.

Rule 2: angle brackets show what a container holds

  • Option<T> holds a maybe-T
  • Box<T> holds an owned heap-allocated T
  • Vec<T> holds many T

Rule 3: outer type matters most for ownership

  • Option<Box<T>>: the box may be absent
  • Box<Option<T>>: the box is always present
  • &Option<T>: borrowed optional value
  • Option<&T>: optional borrowed value

Mini table

Type Meaning
T owned value
&T shared reference to value
&mut T mutable reference to value
Option<T> maybe an owned value
&Option<T> reference to an optional value
Option<&T> maybe a reference
Box<T> owned heap value
Option<Box<T>> maybe a boxed value
Box<Option<T>> boxed optional value
&Box<T> reference to a box