References

Let's take a look at some code that includes a function that takes in a string and returns the length, then, after that function, prints out both the contents of the string and the length:

main.rs
fn main() {
    let s1 = String::from("hello");

    let (s1, len) = calculate_length(s1);

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

fn calculate_length(s: String) -> (String, usize) { // s is a String
    (s.clone(), s.len())
} // Here, s goes out of scope and `drop` is called

That is... sorta gnarly. We could potentially copy s1 into calculate_length instead of returning a tuple, but either way... not great! Luckily, Rust does not actually require us to do this. With Rust, you can pass a value as a reference, which enables the function or variable to get the contents without taking ownership. You do this by putting an ampersand (&) in front of both the type and the variable when it's passed, like so:

main.rs
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 { // s is a reference to a String
    s.len()
} // Here, s goes out of scope. But because it does not have ownership
  // of what it refers to, nothing happens.

The two big changes here are calculate_length(&s1) and calculate_length(s: &String). By default, if something is a reference, it is immutable. You can make a reference mutable by using &mut instead of &. Here's an example:

Knowing this, let's go ahead and redo our code for the team scores (used previously here and here):

In summary, here are the rules for references:

  1. At any given time, you can have either but not both of:

    1. One mutable references

    2. Any number of immutable references

  2. References must always be valid

Last updated