Rust References Rules



References Rules / Borrowing Rules

  1. At any given time, we can have either one mutable reference or any number of immutable references.
  2. References must always be valid

Rule 1

At any given time, we can have either one mutable reference or any number of immutable references.

Breaks this rule will cause errors:

E0499

Erroneous code example:

let mut i = 0;
let mut x = &mut i;
let mut a = &mut i;
x;
// error: cannot borrow `i` as mutable more than once at a time

Output

error[E0499]: cannot borrow `i` as mutable more than once at a time
 --> src/main.rs:4:17
  |
3 |     let mut x = &mut i;
  |                 ------ first mutable borrow occurs here
4 |     let mut a = &mut i;
  |                 ^^^^^^ second mutable borrow occurs here
5 |     x;
  |     - first borrow later used here

For more information about this error, try `rustc --explain E0499`.

E0596

This error occurs because you tried to mutably borrow a non-mutable variable.

Erroneous code example:

let x = 1;
let y = &mut x; // error: cannot borrow mutably

To fix

let mut x = 1;
let y = &mut x;

E0502

A variable already borrowed as immutable was borrowed as mutable.

Errorneous code example

let mut s = String::from("hello");

let r1 = &s; // no problem
let r2 = &s; // no problem
let r3 = &mut s; // BIG PROBLEM

println!("{}, {}, and {}", r1, r2, r3);

Error output

error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
 --> src/main.rs:6:14
  |
4 |     let r1 = &s; // no problem
  |              -- immutable borrow occurs here
5 |     let r2 = &s; // no problem
6 |     let r3 = &mut s; // BIG PROBLEM
  |              ^^^^^^ mutable borrow occurs here
7 | 
8 |     println!("{}, {}, and {}", r1, r2, r3);
  |                                -- immutable borrow later used here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `ownership` due to previous error

Rule 2

References must always be valid.

Dangling References: In languages with pointers, it’s easy to erroneously create a dangling pointer, a pointer that references a location in memory that may have been given to someone else, by freeing some memory while preserving a pointer to that memory. In Rust, by contrast, the compiler guarantees that references will never be dangling references: if you have a reference to some data, the compiler will ensure that the data will not go out of scope before the reference to the data does.

Breaks the rule 2 will cause errors

E0106

This error indicates that a lifetime is missing from a type. If it is an error inside a function signature, the problem may be with failing to adhere to the lifetime elision rules.

Errorneous code examples

fn main() {
    let reference_to_nothing = dangle();
}

fn dangle() -> &String {
    let s = String::from("hello");
    &s
}

E0507

Erroneous code examples:

use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);
    x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
}
error[E0507]: cannot move out of dereference of `Ref<'_, TheDarkKnight>`
  --> src/main.rs:11:5
   |
11 |     x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait

For more information about this error, try `rustc --explain E0507`.
struct Node<T> {
    point: Box<T>,
}

fn main() {
    let n0 = Node {
        point: Box::new(32),
    };
    let r0 = &n0;
    let b0 = r0.point; // cannot move out of `r0.point` which is behind a shared reference
    println!("{}", b0);
}
error[E0507]: cannot move out of `r0.point` which is behind a shared reference
  --> src/main.rs:10:14
   |
10 |     let b0 = r0.point;
   |              ^^^^^^^^
   |              |
   |              move occurs because `r0.point` has type `Box<i32>`, which does not implement the `Copy` trait
   |              help: consider borrowing here: `&r0.point`

For more information about this error, try `rustc --explain E0507`.

It is fine only if you put something back. `mem::replace` can be used for that:

use std::mem;

#[derive(Debug)]
struct Node<T> {
    point: Box<T>,
}

fn main() {
    let mut n0 = Node {
        point: Box::new(32),
    };
    let r0 = &mut n0;
    let b0 = mem::replace(&mut r0.point, Box::new(0));
    println!("{}", b0);
    println!("{:?}", r0);
    println!("{:?}", n0);
}

Ref