Rust References and Borrowing
References and Borrowing
A reference is an address that is supplied as an argument to a function. Borrowing is the same as returning anything we have borrowed after using it for a while. References and borrowing are reciprocal; that is, when one is relinquished, the other likewise terminates.
Why Borrowing?
The following justifies the application of the borrowing concept:
- Multiple references to a single resource are permitted by borrowing, but the resource must still have a “single owner”.
- In C, references are similar to pointers.
- An object is a reference. There are two different kinds of references: changeable and immutable. Although immutable references are copied, mutable references are relocated.
Example
fn main()
{
let str=String::from("javaTpoint");
let len=calculate_length(&str);
println!("length of the string {}",len);
}
fn calculate_length(s:&String)->usize
{
s.len()
}
Output:
length of the string 10
The calculate_length() function in the example above takes ownership of the string str but only provides a reference to it as a parameter.
let str=String::from("javaTpoint");
et len=calculate_length(&str);
Although it does not own the variable str in the example above, &str is a reference to it. As a result, even if the reference leaves its scope, the value it points to will remain intact.
fn calculate_length(s:&String)->usize
s.len()
As long as the control stays in the main() function, the variable’s’ in the example above remains valid. We don’t need to return the values to regain ownership when the variables are supplied to the function as references rather than actual values.
Let's try to modify the borrowed value.
fn main()
{
let x=1;
value_changed(&x)
}
fn value_changed(y:&i32)
{
*y=9;
}
Following is the output of the above program:
Since &x is an immutable reference, it throws an error in the example above. As a result, we are unable to alter y’s value.
Mutable Reference
With the use of a changeable reference, we may correct the preceding issue. References that are subject to change are known as mutable references. Let’s use an example to better grasp this.
fn main()
{
let mut x=1;
value_changed(&mut x);
println!("After modifying, the value of x is {}",x);
}
fn value_changed(y:&mut i32)
{
*y=9;
}
Output:
After modifying, the value of x is 9
The variable y, which is of the &i32 type, points to the changeable reference, &mut x, that we created in the example above. We can now modify the value that the ‘y’ variable references. 9 is assigned, i.e., y=9. As a result, since both variables link to the same memory address, the value x also becomes 9.
Restrictions of Mutable references
Within a given scope, a piece of data can only have one changeable reference.
Example
let mut str=String::from("javaTpoint");
let a= &mut str;
let b= &mut str;
The compiler generates an error in the aforementioned instance because it contains two mutable references, which are not allowed in the Rust programming language.
We cannot have a changeable reference in our application if the immutable reference already exists.
Example
let mut str=String::from("javaTpoint");
let a= &str;
let b=&str;
let c=&mut str;
Because we cannot have a mutable reference when we have an immutable reference, the compiler throws an error in the example above.