Ownership, An exciting concept of Rust (Part-2)

Reading Time: 3 minutes

Hello Readers ! We already read about what is ownership and how memory allocation is done. But for completely understanding ownership, we should know what is borrowing and what are references.

References and Borrowing

fn main() {
    let string1 = String::from("hello");

    let (string2, len) = calculate_length(string1);

    println!("The length of '{}' is {}.", string2, len);
}

fn calculate_length(string3: String) -> (String, usize) {
    let length = string3.len(); // len() returns the length of a String

    (string3, length)
}

The problem in this code is that we have to return the String to the calling function. So we can still use the String after the call to calculate_length because the String was moved into calculate_length.

Here is how you would define and use a calculate_length function that has a reference to an object as a parameter instead of taking ownership of the value:

fn main() {
    let string1 = String::from("hello");

    let len = calculate_length(&string1);

    println!("The length of '{}' is {}.", string1, len);
}

fn calculate_length(string2: &String) -> usize {
    string2.len()
}

These ampersands(&) allow you to refer to some value without taking ownership of it. So they are called References.

For example:

A diagram of &String s pointing at String s1

When the ownership of a value is transferred temporarily to an entity, it is called Borrowing. And then returned to the original owned entity.

We call having references as function parameters borrowing. So what happens if we try to modify something we’re borrowing? We get an error : “cannot borrow `*some_string` as mutable, as it is behind a `&` reference”.

As we know Variables are immutable by default, so references are also immutable. We can not modify references.

Mutable References

If we want to modify a borrowed resource, we can do it by using mutable reference to such resource. &mut is used as prefix before mutable reference. Mutable references can operate only on mutable variables.

But mutable references have one big restriction: you can have only one mutable reference to a particular piece of data in a particular scope. If you try to have more than one mutable reference, you will get “cannot borrow s as mutable more than once at a time” error. This restriction allows for mutation but in a very controlled fashion.

With these restrictions, there are many benefits. Because of this, Rust can prevent data races at compile time.

data race is similar to a race condition and happens when these three behaviors occur:

  • Two or more pointers access the same data at the same time.
  • At least one of the pointers is being used to write to the data.
  • There’s no mechanism being used to synchronize access to the data.

Data races cause undefined behavior and can be difficult to diagnose and fix when you’re trying to track them down at runtime; Rust prevents this problem from happening because it won’t even compile code with data races!

We also cannot have a mutable reference while we have an immutable one. However, multiple immutable references are okay because no one who is just reading the data has the ability to affect anyone else’s reading of the data.

At the point of declaration, scope of the reference starts. And continues through the last time when we use reference.

So this was all about Reference and borrowing. These two concepts of Rust are quite different from other programming languages. Thank you for reading!

If you want to read more content like this?  Subscribe to Rust Times Newsletter and receive insights and latest updates, bi-weekly, straight into your inbox. Subscribe to Rust Times Newsletter: https://bit.ly/2Vdlld7.


Knoldus-blog-footer-image

Written by 

Ayushi is a Software Developer having more than 1.5 year of experience in RUST. Her practice area is Rust and Go. She loves to solve daily coding challenges.

Leave a Reply