However, we may encounter instances where we need to use and modify a value temporarily. We can accomplish this using borrowing. Borrowing is a concept that allows us to borrow a value, use it and once we are done, return it back to its owner in the same state it was when we borrowed it. This means that borrowing does not change the original value.
We borrow a value by referencing it using its memory address and the & operator. We can then pass the reference to a function and use the value as we see fit.
Rules of Referencing
There are two rules for working with references in Rust:
- You can have either mutable references or many immutable references at a time.
- All references must be valid.
Rust Reference and Borrow Value
In Rust, we use the & operator to reference a value address. An example code is as shown below:
let string = String::from("Hello");
let str_len = get_str_length(&string);
println!("String length: {}", str_len);
}
fn get_str_length(string: &String) -> usize {
return string.len();
}
In the code above, we define a variable called “string”. According to the rules of ownership, this variable owns the value “Hello”.
However, we need to use this variable in the function. Since a value can only have an owner at a given time, using it inside the function will transfer ownership. Since we don’t want the ownership to be transferred to the function, we borrow the value using by referencing its owner.
Note that we add the & operator in the function parameter type. This tells rust that we are referencing the value and should give it back after completion.
Mutable References
If we attempt to change a borrowed value, Rust will result in an error. Take the example below:
let string = String::from("Hello");
change_value(&string);
}
fn change_value(string: &String) {
string.push_str(" world!")
}
Running the code above should return an error as:
This is because references are immutable by default. Hence, we may not modify a borrowed value.
We can have a mutable reference that allows us to modify a borrowed value. Consider the example code below:
let mut string = String::from("Hello");
change_value(&mut string);
}
fn change_value(string: &mut String) {
string.push_str(" world!")
}
In the example above, we set the variable “string” t be mutable. We then create a mutable reference using the &mut string in the function call. Note that the function parameter accepts a mutable reference, allowing the function to change the borrowed value.
NOTE: As mentioned, you can have only one mutable reference at a particular time. Attempting to create more than one mutable reference will throw an error as shown:
let mut string = String::from("Hello");
let string2 = &mut string;
let string3 = &mut string;
println!("{} {}", string2, string3);
}
fn change_value(string: &mut String) {
string.push_str(" world!")
}
The code above should return an error as shown:
This feature can help prevent race conditions when borrowing and referencing values.
Conclusion
This article provides a basic understanding of using and working with Rust borrowing and referencing features. You can check the docs to explore further.