References and Borrowing in Rust
Tags: webdev, programming, tutorial, rust
Published: 2024-02-27 14:05:13

## References and Borrowing

In this article, we will see how to use references in Rust. If you want an introduction to Ownership in Rust, in can check the [previous article](https://dev.to/francescoxx/ownership-in-rust-57j2)

In this lesson, we will see:
- Ownership and Functions
- Return Values and Scope
- Introduction to References and Borrowing
- Mutable References
- Multiple Mutable References
- Mutable and Immutable References
- Dangling references
- References Rules

If you prefer a video version
{% youtube Q_0yoX07Fhs %}

<!-- <iframe width="905" height="510" src="https://www.youtube.com/embed/Q_0yoX07Fhs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> -->

All the code is available on [GitHub](https://youtu.be/Q_0yoX07Fhs) (link available in the video description)


## Ownership and Functions

When you pass a variable to a function, you move or copy it. 

If you move it, as it happens with strings, the variable is no longer valid after the function call.

```rust
//ownership and functions
fn main(){
    let i = 5;
    call_integer(i);
    println!("{}", i);

    let s = String::from ("Hello, World!");
    call_string(s);
    println!("{}", s);
}
```

[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wftpe5htx7ylrrm428bp.png)](https://youtu.be/Q_0yoX07Fhs)

## Return Values and Scope

When a function returns a value, it gives ownership of the value to the calling function. 

We can also have a function that has ownership but gives it back to the calling function. 

```rust
//ownership and functions
fn main(){
    let s1 = give_ownership();
    let s2 = String::from("hello");  // s2 comes into scope
    let s3 = take_and_give_back(s2); // s2 is moved into take_and_give_back, it returns s3

    println!("s1: {}", s1);
    println!("s2: {}", s2); // error: value used here after move
    println!("s3: {}", s3);
}

fn give_ownership() -> String {
    let some_string = String::from("hello");
    some_string
}

fn take_and_give_back(a_string: String) -> String {
    a_string
}
```

Let's type `cargo run -q` and see the output:

[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cbw8upxwx1kjnvx7dx3e.png)](https://youtu.be/Q_0yoX07Fhs)


But if we try to use the `s2` variable after the function call, we get an error. 

[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eoiezwv9xk5i6sapox5o.png)](https://youtu.be/Q_0yoX07Fhs)

So how can we solve this? Let's see an example.

### A first example of getting the ownership back

One first solution might be this: we can return the value passed in input back, using a tuple.

For example, if we want to calculate the length of a string, we can return the string and its length. 

```rust
fn main(){
    let s1 = String::from("hello");
    let (s2, len) = calculate_length(s1);
    println!("The length of '{}' is {}", s2, len);
}

fn calculate_length(s: String) -> (String, usize){
    let length = s.len();
    (s, length)
}
```

This "works", but it's not the best solution.

[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gksowco1ua3l7062frmz.png)](https://youtu.be/Q_0yoX07Fhs)

This solution is tedious and error-prone. 

Rust has a feature called references that allows you to refer to some value without taking ownership of it. 

Let's see how to modify the previous example using references.

## Introduction to References and Borrowing

Modify the code above to use references instead of taking ownership of the string. 

```rust
fn main(){
    let s1 = String::from("hello");
    let len = calculate_length(&s1);
    println!("The length of '{}' is {}", s1, len);
}

fn calculate_length(s: &String) -> usize{
    let length = s.len();
    length
}
```

Explanation:  `&s1` creates a reference to the value of `s1` but does not take ownership of it.

In the signature of `calculate_length`, `s: &String` means that `s` is a reference to a `String`.

If we type `cargo run -q`, we get the expected output:

[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bvag6sg7tw2ae0nld8pe.png)](https://youtu.be/Q_0yoX07Fhs)

We are getting the same outut as before, but now we are not taking ownership of the string.

Here is a schema of what happens when we pass a reference to a function:


[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5h98ihajfjfsrci7zwju.png)](https://youtu.be/Q_0yoX07Fhs)

IMPORTANT: The action of passing a reference to a function is called `Borrowing`.

## Mutable References

Can we change the value of a reference? 

```rust
fn main(){
    let s = String::from("hello");
    change(&s);
    println!("{}", s);
}

fn change(s: &String){
    s.push_str(", world");
}

```
But here we get an error:

[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z9oz1ds0utqkoat4jvtq.png)](https://youtu.be/Q_0yoX07Fhs)

References are immutable by default.

But we can make them mutable by using `&mut` instead of `&`.

Of course, the value of the variable must be mutable as well.

```rust
//mutable references
fn main(){
    let mut s = String::from("hello");
    modify(&mut s);
    println!("{}", s);
}

fn modify(s: &mut String){
    s.push_str(" world");
}
```

## Multiple Mutable References

Can we have multiple mutable references to the same variable?

```rust
fn main() {
    let mut s = String::from("hello");

    let s1 = &mut s;
    let s2 = &mut s;

    println!("{}, {}", s1, s2);
}
```

This code is not valid. 

[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/856dyqrppwq7qmsfg7g9.png)](https://youtu.be/Q_0yoX07Fhs)

This should surprise you. In many programming languages, having multiple references to the same variable is not a problem. But this can lead to problems at runtime.

In Rust, the compiler prevents this from happening.

Of course, we can have multiple mutable references, but in different scopes.

```rust
fn main() {
    let mut s = String::from("hello");

    {
        let s1 = &mut s;
        s1.push_str(" world");
    }   //s1 goes out of scope here

    let s2 = &mut s;
    s2.push_str("!");

    println!("{}", s2);
}
```

This code is valid.

## Mutable and Immutable References

Let's try to mix mutable and immutable references.

```rust
fn main() {
    let mut s = String::from("hello");

    let s1 = &s; //immutable borrow
    let s2 = &s; //immutable borrow

    let s3 = &mut s; //mutable borrow

    println!("{}, {}, {}", s1, s2, s3);
    //throws error: cannot borrow `s` as mutable because it is also borrowed as immutable
}
```

This code is not valid: we cannot have a mutable reference while we have immutable references.

[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sehvgh8sk5x2n4a93wa2.png)](https://youtu.be/Q_0yoX07Fhs)

But if we use the immutable references before the mutable reference, the code is valid.

```rust
fn main() {
    let mut s = String::from("hello");

    let s1 = &s; //immutable borrow
    let s2 = &s; //immutable borrow

    println!("{} and {}", s1, s2);

    let s3 = &mut s; //mutable borrow

    println!("{}", s3);
}
```

This code is valid because the immutable borrows are not used after the mutable borrow. 

## Dangling references

A Dangling reference is a reference that points to an invalid memory.

```rust
fn main() {
    let s  = dangle();
}

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

In this case, the reference `&s` is returned, but `s` goes out of scope at the end of the function.

[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oury4og6ym9l22evnloq.png)](https://youtu.be/Q_0yoX07Fhs)


To solve this problem, we can return the string directly. 

```rust
fn main() {
    let s = no_dangle();
    println!("{}", s);
}

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

[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lp0pvla1psurxmhlnoxp.png)](https://youtu.be/Q_0yoX07Fhs)

This code is valid.

## References Rules

There are 2 main rules for references:

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

- References must always be valid.

[![References and borrowing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e18qhylnq94bqqns6dno.png)](https://youtu.be/Q_0yoX07Fhs)

## Conclusion

In this article, we have seen how to use references in Rust.

We have seen how to pass references to functions, how to use mutable references, and the rules for using references.

If you prefer a video version
{% youtube Q_0yoX07Fhs %}

<!-- <iframe width="905" height="510" src="https://www.youtube.com/embed/Q_0yoX07Fhs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> -->

All the code is available on [GitHub](https://youtu.be/Q_0yoX07Fhs) (link available in the video description)

You can find me here: [Francesco](https://francescociulla.com)