How to use references in Rust

A reference of a variable is a pointer that leads to that variable. Rust uses the concept of ownership, which is associated with how references are used.

Syntax

An ampersand (&) is used with a variable’s name while passing its reference instead of its value to a function. The function’s signature should also have an ampersand with the type of argument that receives the reference. When a function takes in a reference as a parameter, it is called borrowing.

// Passing a reference of 'x':
foo(&x);

// foo borrows the value of 'x':
fn foo(a: &i32) {
  // Do something
}

Types of references

There are two types of references in Rust:

1. Immutable

A reference is immutable by default. Similar to an immutable variable, an immutable reference variable cannot change the value of anything it refers to. For example, in the code below, the function foo() is not allowed to change the value of the title string after borrowing it:

let title = String::from("hello");
foo(&title);

fn foo(ptr: &String) {
    // Error while modifying 'title':
    ptr.push_str(", world");
}

2. Mutable

If the mut keyword is used with the & symbol, we can modify a borrowed value:

The variable itself also has to be mutable for it to be changed after it has been borrowed.

fn main() {
let mut x = 10;
println!("x = {}", x);
// Pass 'x' as a mutable reference:
change_value(&mut x);
// Print new value of 'x':
println!("New value of x = {}", x);
}
fn change_value(s: &mut i8) {
// Dereferencing 's' and changing its value:
*s = 5;
}

Some restrictions

  1. Multiple mutable references to the same variable cannot exist within one scope:
let ref1 = &mut x;
let ref2 = &mut x;
  • This restriction prevents two references from changing the value of x simultaneously.
  1. An immutable reference and a mutable reference to the same variable cannot exist at the same time because a function borrowing an immutable reference doesn’t expect a change in the referred value. For example:
let ref1 = &x;
let ref2 = &mut x;

// Pass immutable ref1 to read():
read(ref1);

fn read(i: &i8) {
    // Use value of 'x' using immutable reference 'i'
}
  • However, the lifetime of an immutable reference only lasts till its last usage. So, the following code won’t generate an error because the lifetime of ref1 ends at line 5, i.e., before the mutable ref2 was created.
fn main() {
let mut x = 10;
let ref1 = &x;
read_value(ref1); // Lifetime of ref1 ends here
let ref2 = &mut x;
change_value(ref2);
// Print new value of 'x':
println!("New value of x = {}", *ref2);
}
fn read_value(i: &i8) {
// Use immutable reference 'i':
println!("x = {}", *i);
}
fn change_value(i: &mut i8) {
// Use mutable reference 'i':
*i = 5;
}
Copyright ©2024 Educative, Inc. All rights reserved