I'm getting a Rust compile error from the borrow checker, and don't know how to fix it.
The code below is simple, and no problem with similar code in C++.
fn main() {
let mut nums = vec![1, 2, 3];
if let Some(x) = nums.last() {
nums.push(*x);
}
}
Here is the error:
message: 'cannot borrow `nums` as mutable because it is also borrowed as immutable (4, 9)'
The borrow check is Rust's "secret sauce" – it is tasked with enforcing a number of properties: That all variables are initialized before they are used. That you can't move the same value twice. That you can't move a value while it is borrowed.
An Example of Borrowing in Rust You can borrow the ownership of a variable by referencing the owner using the ampersand (&) symbol. Without borrowing by referencing, the program would panic. It would violate the ownership rule that a value can have one owner, and two variables cannot point to the same memory location.
You can easily notice similarities between Rust and C++ syntax, but Rust offers a higher level of memory safety without using a garbage collector. Not for the first time, Rust has been named the most loved language—it gained more than 86% of developers' votes.
Rust supports a concept, borrowing, where the ownership of a value is transferred temporarily to an entity and then returned to the original owner entity. The main function invokes a function print_vector(). A vector is passed as parameter to this function.
When you call .last()
you borrow nums
as immutable, as mutating it would invalidate the reference x
that you hold. You then call .push
, which borrows nums
as mutable.
The problem is that you now have an immutable and a mutable borrow of the same value at the same time, which is against rusts memory safety guarantees (multiple readers or one single writer guarantee that you will never have invalid memory anywhere).
fn main() {
let mut nums = vec![1, 2, 3];
if let Some(x) = nums.last() { // Immutable borrow starts here
nums.push(*x); // Mutable borrow starts here
} // Immutable and mutable borrows end here
}
The solution would be to lower the scope of the immutable borrow by immediately dropping the reference of its result, as per @DanielSanchez's example:
let mut nums = vec![1, 2, 3];
if let Some(&x) = nums.last() { // Immutable borrow starts and ends here
nums.push(x); // Mutable borrow starts here
} // Mutable borrow ends here
You can dereference the reference in the guard clause:
fn main() {
let mut nums = vec![1, 2, 3];
if let Some(&x) = nums.last() {
nums.push(x);
}
}
Rust has a powerful pattern matching feature, you can unpack almost everything if you know its type. Check the Rust pattern matching documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With