Borrowing in Rust

In layman's terms, please explain borrowing in Rust, then present a well commented coding example to help the reader to better understand the term.

 

Borrowing in Rust: A Simple Explanation

In Rust, "borrowing" refers to the process of allowing a function or part of your program to temporarily access a variable without taking ownership of it. This ensures that you can use data without moving it, which would otherwise make it unusable in the original scope.

Rust uses two types of borrowing:

  1. Immutable Borrowing (&): You can borrow the value of a variable, but you cannot modify it. Multiple immutable borrows are allowed.
  2. Mutable Borrowing (&mut): You can borrow the value and modify it, but only one mutable borrow is allowed at a time to prevent data races and ensure safety.

The rules of borrowing in Rust are:

  • You can have multiple immutable borrows (&) OR
  • You can have one mutable borrow (&mut), but not both at the same time.

This ensures memory safety by preventing unexpected changes to data while it is being used elsewhere.

Example Code

fn main() {
    // Create a variable with ownership of a string
    let mut my_string = String::from("Hello, Rust!");

    // Borrow the value immutably (cannot modify)
    // We can have multiple immutable borrows
    let length = calculate_length(&my_string); // Passing a reference to my_string
    println!("The length of '{}' is {}.", my_string, length);

    // Mutable borrow (can modify the value)
    // Only one mutable borrow is allowed at a time
    append_world(&mut my_string); // Passing a mutable reference
    println!("After modification: '{}'", my_string);
}

// Function that takes an immutable reference to a string
// It can read the string but cannot modify it
fn calculate_length(s: &String) -> usize {
    s.len() // Return the length of the string
}

// Function that takes a mutable reference to a string
// It can modify the original string
fn append_world(s: &mut String) {
    s.push_str(" World!"); // Appends " World!" to the string
}

Commented Explanation of the Code

  1. We declare a mut variable my_string so it can be modified later.

  2. Immutable Borrowing:

    • In the calculate_length function, we pass &my_string. This is an immutable reference. The function can access my_string but not change it.
    • Multiple immutable references (borrows) can exist, so you can call the calculate_length function as many times as you want without changing the original data.
  3. Mutable Borrowing:

    • In the append_world function, we pass &mut my_string, which allows us to modify the original string by appending " World!" to it.
    • Only one mutable borrow can exist at a time, which prevents data races and keeps your program safe from unexpected behavior.

This combination of borrowing rules helps Rust ensure memory safety without needing a garbage collector.

You should also read:

"Hello World" in C and Rust

Please compare and contrast "Hello World" in the C and Rust programming languages. Certainly! Let's compare and contrast the "Hello World" programs in…