I am new to Rust and I cannot solve this simple problem: Consider following code:
let mut a = vec![String::from("aa"), String::from("bb")];
a[0] = &*a[1];
Borrow checker rightfully complains about me having both immutable and mutable borrows here. It also suggests me:
help: try adding a local storing this...
--> src\main.rs:61:15
|
61 | a[0] = &*a[1];
| ^^^^
help: ...and then using that local here
--> src\main.rs:61:5
|
61 | a[0] = &*a[1];
| ^^^^^^^^^^^^^^
I do not really understand what that means. Do I really need to clone the string to perform such an easy operation? (That would result in 2 overall copies: into temporary and then back into a[0], instead of optimal 1 copy straight into a[0])
CodePudding user response:
Naively, like this (no reason to dereference a[1]
):
fn main() {
let mut a = vec![String::from("aa"), String::from("bb")];
a[0] = &a[1];
}
Sadly, as you noticed, this creates a problem with the borrow checker. Modifying a[0]
borrows it mutably, while you also need to borrow a[1]
immutably to append it. And borrowing a
both mutably and immutably at the same time isn't allowed:
error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
--> src/main.rs:3:14
|
3 | a[0] = &a[1];
| ---------^---
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
The reason is that Rust doesn't know that a[0]
and a[1]
are independent variables. This behavior is intentional and important, as it prevents some cases that could lead to undefined behavior. Rust has a zero-undefined-behavior guarantee.
You can split the array into two independently mutable parts via the split_at_mut
function, though. This works because Rust can now guarantee that both parts are independent. Borrowing them sequentially makes it impossible for (current) Rust to prove that.
fn main() {
let mut a = vec![String::from("aa"), String::from("bb")];
let (a_left, a_right) = a.split_at_mut(1);
a_left[0] = &a_right[0];
println!("{:?}", a);
}
["aabb", "bb"]
Note that the split_at_mut
is almost free. It doesn't actually copy anything, it just creates two slices that point at two non-overlapping parts of the array. It doesn't cause any performance overhead.