Beginner's guide to Rust references
Tags: rust, beginners
Published: 2023-08-05 16:32:09

You probably know that this code does not compile
```rs
fn main() {
    let my_vec = vec![1, 2, 3];
    let my_other_vec = my_vec;
    println!("{:?}", my_vec); // error!
}
```
but this code does:
```rs
fn main() {
    let my_number = 1;
    let my_other_number = my_number;
    println!("{:?}", my_number);
}
```

It happens due to the key principle of Rust language: the ownership system. Two main things happen here: 

- `Vec<T>` does not implement the `Copy` trait, so its value will be moved to `my_other_vec` and we won't be able to use `my_vec` after that.

-  `i32` does implement the `Copy` trait, so its value will be copied to `my_other_number`, and we can still use the `my_number` variable.

However, in the real world, we often deal with types that don't implement the Copy trait, and having to move things around multiple times would become a real headache if there was no alternative. But Rust has a way to use values without moving them: borrowing.

```rs
fn main() {
    let my_vec = vec![1, 2, 3];
    add_one(&my_vec)
}

fn add_one(v: &Vec<i32>) {
    println!("{:?}", v);
}
```

If the `add_one` function were to accept a Vec<i32> instead of a &Vec<i32>, any vec passed to this function would be moved into it, rendering the original value unusable. Since this is not the behavior we want, our function now accepts a reference to a value, instead of the value itself.

## Immutable references (`&T`) - reading a value
The previous snippet shows a scenario in which we need to borrow a value only for reading, without modifying it. Just like variables in Rust, which are immutable unless you put the keyword `mut` in the declaration, references are also immutable by default.
This behavior guarantees that we do not accidentally change the value, since we are only reading from it. For this reason, we can have as many **immutable** references as we want - and that's the reason why the type `&T` is also called a **shared reference.**

However, the use of immutable references follows some additional rules.
Let's imagine a scenario in which we need to create a `Vec<i32>` based on another `Vec<i32>`, but we only have access to the reference pointing to the `Vec`.

```rs
let my_vec_ref: Vec<i32> = &my_vec;
``` 
There is a type mismatch here, since `my_vec_ref` is supposed to be a `Vec`, not a _reference_ to one. However, there is a solution: Rust provides the "inverse" operator of `&`: the `*` operator, which lets us access the value behind a reference!

```rs
fn main() {
    let my_vec: Vec<i32> = vec![1, 2, 3];
    let my_vec_ref = &my_vec;
    let another_vec = *my_vec_ref; // oops!
}
```
_... but not to move it._

The code above gives us the following error:
```
cannot move out of `*my_vec_ref` which is behind a shared reference
move occurs because `*my_vec_ref` has type `Vec<i32>`, which does not implement the `Copy` trait
```

Alright, we know that `Vec<i32>` does not implement the `Copy` trait and stuff, but what is this error actually telling us?

### Moving _out_
The `=` operator creates an _assignment expression_. According to Rust docs, an assignment expression _moves_ a value into a specified place.

Things are pretty straightforward when we are dealing with straightforward types, but a reference is what we call an _indirection type_ - a type that has a "layer" between you and the real data. In this case, we can imagine the reference as a _wrapper_ for the data. Due to its immutability, we are not allowed to either **change** what's inside of it or **move** what's inside of it. In other words, we can't **"move out"**.
It also implies that we can only move things from values **we own**, never from values we **borrow** - which is another way to say the same thing.

Additionally, in Rust the `.` operator automatically dereferences reference types, causing the same error to happen when we try to do things such as the code below.
```rs
struct MyStruct {
    str_vec: Vec<i32>
}

fn main() {
    let strct = MyStruct { str_vec: vec![1, 2, 3]};
    let strct_ref = &strct;
    let my_vec = strct_ref.str_vec; // error!
}
```

This behavior is useful when talking about methods that take `self` by reference, ommiting the use of `*` operator:

```rs
struct MyStruct { n: u32 };

impl MyStruct {
    // no need to type (*self).n
    fn method(&self) -> u32 { self.n }
}

let x = MyStruct { n: 12 };
// Here the compiler automatically references self,
// so that there's no need to write (&x).method()
let n = x.method();

```

### The solution
Back to one of our previous examples:
```rs
fn main() {
    let my_vec: Vec<i32> = vec![1, 2, 3];
    let my_vec_ref = &my_vec;
    let another_vec: Vec<i32> = *my_vec_ref; // oops!
}

```
In cases like this, the error messages may contain some misleading instructions, such as the following:
```
consider borrowing here: `&*my_vec_ref
```
This is not possible here, since it means assigning a `&Vec<i32>` to a value that has type `Vec<i32>`.  
Therefore, the solution when this error happens is to _clone_ the value - so that you get a copy from it without moving it.
```rs
let another_vec: Vec<i32> = my_vec_ref.clone(); 
```

## Mutable references (`&mut T`)
Modifying a non-copy value follows the logic of moving or borrowing. You can either move the value in order to modify it, or use a **mutable reference** (borrow) to do so.
Let's create a function that modifies a value using a `&mut T`:

```rs
fn main() {
    let mut my_vec = vec![1, 2, 3];
    let ref_my_vec = &mut my_vec;
    add_one(ref_my_vec);
    println!("{:?}", my_vec);
}

fn add_one(v: &mut Vec<i32>){
    v.push(1);
}
```

When we assign a mutable reference to `ref_my_vec`, it means that this variable _points to_ an **existing** value, instead of owning a new value. Therefore, modifying `ref_my_vec` is equivalent to directly modify `my_vec`. We can say that a mutable reference provides us with write access to a value. 
However, since the only way to _securely_ modify a value is to have an **unique write access** to it (think about data races), Rust does not allow us to have more than one mutable reference to the same value simultaneously.
```rs
    let ref_my_vec = &mut my_vec;
    let another_ref = &mut my_vec;
    // cannot borrow `my_vec` as mutable more than once at a time
```

This is the reason why a mutable reference is also called an **unique reference.** 
Similarly to shared references, Rust also does not allow us to move _out_ of mutable references. In fact, moving out from any kind of reference - mutable or not - **is not allowed**. 

```rs
fn main() {
    let mut my_vec: Vec<i32> = vec![1, 2, 3];
    let my_vec_ref = &mut my_vec;
    let another_vec = *my_vec_ref; // oops!
}
```

```
cannot move out of `*my_vec_ref` which is behind a mutable reference
move occurs because `*my_vec_ref` has type `Vec<i32>`, which does not implement the `Copy` trait
```


## Mutability with references
### What is the difference between `p: &T`, `mut p: &T`, `p: &mut T` and `mut p: &mut T`?

When talking about a variable whose type is a reference, it is important to differentiate what does it mean to change what _the reference points to_ and what _our variable points to._
Therefore, you can do the following:
```rs
let vec_number = vec![1, 2, 3];
let another_vec = vec![2, 3, 4];
let mut ref_vec = &vec_number;
ref_vec = &another_vec;
```
Let's see what is happening here. 
Although we _cannot_ change the data the `ref_vec` variable points to, we can make `ref_vec` point to another data (as long as it has the same type of the data previously assigned). 
Therefore, when we put the `mut` keyword in the **left side** of an _assignment expression_, we are telling Rust that we are going to reassign that variable to another value.

| Type          |   Can reassign the variable | Can change the data the variable points to |
|---------------|-----------------------------|--------------------------------------------|
| p: &T         | ❌                           | ❌                                          |
| mut p: &T     | ✅                           | ❌                                          |
| p: &mut T     | ❌                           | ✅                                          |
| mut p: &mut T | ✅                           | ✅                                          |