This question already has answers here:
How to get mutable references to two array elements at the same time?
(8 answers)
Closed 8 months ago.
I'm solving a problem from Leetcode and encountered the fact that Rust won't let me execute it efficiently. What am I doing wrong? I know about the book article about references and borrowing and would like to know how to solve this problem despite the peculiarities of the language.
I am trying to create one reference for a vec that should change and another for a vec that will not change. Rust won't let me do that. The program works, but only when using .clone(), which will be very slow and not necessary (last_row does not change anywhere, only the values are derived from there).
Here is the working code:
use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
let last_row = & triangle[i+1].clone();
let current_row = &mut triangle[i];
for j in 0..current_row.len() {
current_row[j] = cmp::min(last_row[j], last_row[j+1]) + current_row[j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}
As you can see, I used .clone() to fix the borrow checker errors that show up when you try to write a program using references:
use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
let current_row = &mut triangle[i];
let last_row = &triangle[i+1];
for j in 0..current_row.len() {
current_row[j] = cmp::min(last_row[j], last_row[j+1]) + current_row[j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}
Terminal:
error[E0502]: cannot borrow `triangle` as immutable because it is also borrowed as mutable
--> src\main.rs:6:25
|
5 | let current_row = &mut triangle[i];
| -------- mutable borrow occurs here
6 | let last_row = &triangle[i+1];
| ^^^^^^^^ immutable borrow occurs here
7 | for j in 0..current_row.len() {
| ----------------- mutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
However, when trying to write a program poorly everything works without any problems:
use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
for j in 0..triangle[i].len() {
triangle[i][j] = cmp::min(triangle[i+1][j], triangle[i+1][j+1]) + triangle[i][j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}
You can accomplish this via the split_at_mut() method, which comes from the primitive slice type (which Vec auto-derefs to). This method allows you to safely take a mutable slice and split it into two mutable slices at a given index, since it's guaranteed that the two slices won't overlap. (Note this is zero-copy, as slices are just fat pointers borrowing an existing contiguous sequence.)
The two slices then are independent for the purposes of borrow checking, so you can borrow mutably from both slices at the same time (or, in your case, mutably from one and immutably from the other).
use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
let (left, right) = triangle.split_at_mut(i + 1);
let current_row = left.last_mut().unwrap();
let last_row = right.first().unwrap();
for j in 0..current_row.len() {
current_row[j] = cmp::min(last_row[j], last_row[j+1]) + current_row[j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}
Yes, that's the thing with Rust -- you have to code in a way that the compiler can tell it is safe. Sometimes that requires a bit of thought, but often in the end you have code that is cleaner than you would have written otherwise.
Imagine having a function that could walk through items two at a time, calling a function you specify on them, with the first being immutable, and the second being mutable. Call it pairs_mut, and calling it with function f on a,b,c,d it would result in calls to f(&a, &mut b), f(&b, &mut c), and f(&c, &mut d). A non-generic version is not that hard to write. I am hesitant to put the code here because you are trying to learn from the exercise.
NOTE: I suspect that such a facility (or perhaps something more general) exists somewhere in the Rust ecosystem, but I have looked in Iterator and the itertools crate and didn't find anything. If you know of an existing facility like this, please share a link in a comment. Otherwise perhaps I should try to get something added to itertools.
Now given pairs_mut, I hope you can see that minimum_total could run it on triangle.rev() and do that bit of dynamic programming to come up with the minimum sum. Let me know if you want me to put some actual code here, but I encourage you to try it yourself first.
This question already has answers here:
How can I swap in a new value for a field in a mutable reference to a structure?
(2 answers)
Cannot move out of borrowed content when trying to transfer ownership
(1 answer)
Temporarily move out of borrowed content
(3 answers)
How to write a trait bound for adding two references of a generic type?
(1 answer)
Closed 2 years ago.
Is there a way to write this function without requiring AddAssign or Clone on T?
use std::ops::Add;
fn increment<T: Add<isize, Output = T>>(x: &mut T) {
*x = *x + 1;
}
As written, I get the error:
error[E0507]: cannot move out of `*x` which is behind a mutable reference
--> src/lib.rs:4:10
|
4 | *x = *x + 1;
| ^^ move occurs because `*x` has type `T`, which does not implement the `Copy` trait
Based on #Shepmaster's response in the comments, I gather that this is impossible without changing the function signature because the function being applied may panic leaving x in a memory-unsafe state if the panic is recovered from.
However by adding the Default constraint it becomes possible using mem::replace.
use std::mem;
use std::ops::Add;
fn increment<T: Default + Add<isize, Output = T>>(x: &mut T) {
let y = mem::replace(x, Default::default());
*x = y + 1;
}
Now if add panics, x will have the default T.
This question already has answers here:
How can I modify a collection while also iterating over it?
(2 answers)
Closed 3 years ago.
Here is a simple artificial example to illustrate the problem:
fn sum_slice(v: &[i32]) -> i32 {
v.iter().sum()
}
fn sum_previous(v: &mut [i32]) {
for (i, val) in v.iter_mut().enumerate() {
*val = sum_slice(&v[0..i]);
}
}
fn main() {
let mut v = vec![1,1,1,1,1,1,1];
sum_previous(&mut v);
println!("{:?}", v);
}
Ideally the intention is that sum_previous will take the slice provided and replace each element with the sum of previous ones.
But this is generating the error:
error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as
mutable
--> src/main.rs:7:27
|
6 | for (i, val) in v.iter_mut().enumerate() {
| ------------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
7 | *val = sum_slice(&v[0..i]);
| ^ immutable borrow occurs here
Rust playground link
I understand the problem that Rust is restricting us to have exactly one mutable reference and no immutable at the same time. I can also come with different solutions such as using another vector to store the results, but the question is not how to work around it but what is the acceptable pattern here?
FWIW the original problem is implementation of a cellular automaton, where a grid to be processed and each cell to be updated based on its neighbours. In that case the grid is borrowed mutably, while the function to calculate the update is expecting an immutable reference.
You can do this using split_at_mut:
fn sum_previous(v: &mut [i32]) {
for i in 1..v.len() {
let (head, tail) = v.split_at_mut(i);
tail[0] = sum_slice(head);
}
}
(Permalink to the playground)
This question already has answers here:
Why is indexing a mutable vector based on its len() considered simultaneous borrowing?
(1 answer)
Cannot borrow as mutable because it is also borrowed as immutable
(3 answers)
Closed 3 years ago.
I am trying to obtain a reference to the last value of a vector to simplify referencing it in the following code.
fn calculate_errors(&mut self, targets: &[f64]) -> () {r
let ref mut last_layer = self.vector[self.vector.len() - 1];
for i in 0..last_layer.len() {
last_layer[i].error = targets[i] - last_layer[i].value;
}
}
In my attempt here I get the error:
error[E0502]: cannot borrow self.vector as immutable because
it is also borrowed as mutable
What would be the proper way to do this? How could I fix this?
This question already has answers here:
Borrow checker doesn't realize that `clear` drops reference to local variable
(6 answers)
What are the options to end a mutable borrow in Rust?
(1 answer)
Closed 3 years ago.
I have a problem with the borrow checker in the following scenario: First I store an immutable reference to a mutable variable x, which I later use elsewhere in my code. Now I come to a point where I want to change the value of x. Knowing that there is an immutable reference to it inside foo.bar, first I remove the reference by calling foo.bar.clear().
Now that there are no immutable borrows, I'd expect that I can mutate the object, but that's not case. I assume that the problem is that the compiler has no way of knowing that clear() drops the references inside foo.bar, but I'm clueless how to proceed in this situation.
Minimal example:
struct Foo<'a> {
bar: Vec<&'a i32>
}
fn main() {
let mut x = 42;
let mut foo = Foo { bar: vec![&x] };
// Do immutable stuff with foo.bar[0]... then:
foo.bar.clear();
x += 1;
foo.bar.push(&x);
println!("X is: {}", foo.bar[0]);
}
playground