The Rust Programming Language — References and Borrows — Understanding Values by Reference and Borrows
The pain of use after move errors finally ends!
In one of our previous examples we say an instance where use after move error was observed. Please have a look at the snippet which causes that error:
fn print_years(years: Vec<i32>) {
for year in years.iter() {
println!("{}", year);
}
}
fn main() {
let years = vec![2001, 2002, 2003, 2004]; // alloc()
print_years(years); // transfer the ownership of years to print_years()
print_years(years);
}You must be aware that the variable years deallocation responsibility is with print_years(). So when the first time the method print_years() is called, years memory is marked as available. So when the method print_years() runs the second time, we get the use after move error.
We understood that this can be solved by making the print_years() return years and we create a new copy of the variable years2 as shown below:
fn print_years(years: Vec<i32>) {
for year in years.iter() {
println!("{}", year);
}
return years;
}
fn main() {
let years = vec![2001, 2002, 2003, 2004]; // alloc()
let years2 = print_years(years); // transfer the ownership of years to print_years()
let years3 = print_years(years2);
}We all agree that making such redundant variables is unpleasant and the names also do not follow the best practices. We can solve this problem by using References and Borrowing concepts. Have a look at the below code snippet:
fn print_years(years: &Vec<i32>) {
for year in years.iter() {
println!("{}", year);
}
}
fn main() {
let years = vec![2001, 2002, 2003, 2004]; // alloc()
print_years(&years); // transfer the ownership of years to print_years()
print_years(&years);
}Observations:
- Notice a new character being used across the entire snippet
&. This is known as a character to represent a Reference Type or a Reference Value. &Vec<i32>is a Reference Type and &years is a Reference Value.
This usage of & also solves the problem. Usage of & helps us avoid the cloning that we do and all those unwanted returns we make just to satisfy the compiler.
What’s going on with &?
&Vec<i32>is not a vector ofi32but it’s a reference ofVec<i32>.- With references we want to pass read-only access rights of the values that we pass around the functions.
- When we do this, we dont allow the function accessing the reference values to manage the de-allocation of memory for the passed variable.
- We mean to give the read-only access to the variable only temporarily and the ownership still to de-allocate the memory still resides with the parent function.
- So when we want to find a length of the vector, we call
.len()on it. The signature of the function is something like:fn len(&self) -> usize. So.len()does not get rights to de-allocate memory for the vector. They get only a read-only access. - What do we actually mean by passing
&years— temporarily give access toprint_years()foryearsbut the ownership of de-allocation still stays withmain()function.print_years()borrowsyearsfor doing something (read) with it but not everything (de-allocation).
We can’t turn a borrow checker off in Rust and we need to figure out someway to deal with it.
I hope you enjoyed this article about References and Borrowing in Rust. Please share your feedback in the comments section.
You can subscribe to my newsletter about The Rust Programming Language here. You can read about all the articles in this series here.






