I want to use a double For loop to compare each element with each and if these properties are the same, make a change to the objects. Below is a little demo code of what I want to do.
But the Rust compiler tells me here that I can't have 2 mutable references from the same object. How can I implement the whole thing differently?
fn main() {
struct S {
a: i32
}
let mut v = vec![S{a: 1}, S{a: 1}, S{a: 1}];
let size = v.len();
for i in 0..size {
for j in 0..size {
if i == j {
continue;
}
let a = &mut v[i];
let b = &mut v[j];
if a.a == b.a {
a.a = 5;
}
}
}
}
Console:
error[E0499]: cannot borrow `v` as mutable more than once at a time
--> src\main.rs:35:26
|
34 | let a = &mut v[i];
| - first mutable borrow occurs here
35 | let b = &mut v[j];
| ^ second mutable borrow occurs here
36 |
37 | if a.a == b.a {
| --- first borrow later used here
First thing to note is that you don't need two mutable references since you are only mutating v[i].
Writing it like this will create two immutable borrows and inside the if a mutable borrow:
if v[i].a == v[j].a {
v[i].a = 5;
}
Being very explicit this is what is happening (but its nicer the other way):
let a = &v[i];
let b = &v[j];
if a.a == b.a {
let mut_a = &mut v[i];
mut_a.a = 5;
}
One of the rules of the borrow checker is that no two mutable borrows can exist to the same thing at the same time.
Related
I want to get two values from a hashmap at the same time, but I can't escape the following error, I have simplified the code as follows, can anyone help me to fix this error.
#[warn(unused_variables)]
use hashbrown::HashMap;
fn do_cal(a: &[usize], b: &[usize]) -> usize {
a.iter().sum::<usize>() + b.iter().sum::<usize>()
}
fn do_check(i: usize, j:usize) -> bool {
i/2 < j - 10
}
fn do_expensive_cal(i: usize) -> Vec<usize> {
vec![i,i,i]
}
fn main() {
let size = 1000000;
let mut hash: HashMap<usize, Vec<usize>> = HashMap::new();
for i in 0..size{
if i > 0 {
hash.remove(&(i - 1));
}
if !hash.contains_key(&i){
hash.insert(i, do_expensive_cal(i));
}
let data1 = hash.get(&i).unwrap();
for j in i + 1..size {
if do_check(i, j) {
break
}
if !hash.contains_key(&j){
hash.insert(j, do_expensive_cal(j));
}
let data2 = hash.get(&j).unwrap();
let res = do_cal(data1, data2);
println!("res:{}", res);
}
}
}
Playground
error[E0502]: cannot borrow hash as mutable because it is also borrowed as immutable
--> src/main.rs:26:8
|
19 | let data1 = hash.get(&i).unwrap();
| ------------ immutable borrow occurs here
...
26 | hash.insert(j, vec![1,2,3]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
29 | let res = do_cal(data1, data2);
| ----- immutable borrow later used here
For more information about this error, try rustc --explain E0502.
error: could not compile playground due to previous error
Consider this: the borrow checker doesn't know that hash.insert(j, …) will leave the data you inserted with hash.insert(i, …) alone. For the borrow checker, hash.insert(…) may do anything to any element in hash, including rewriting or removing it. So you can't be allowed to hold the reference data1 over hash.insert(j, …).
How to get over that? The easiest is probably to move let data1 = hash.get(…) so it doesn't have to live for so long:
let data1 = hash.get(&i).unwrap();
let data2 = hash.get(&j).unwrap();
let res = do_cal(data1, data2);
This will of course look up data1 every loop iteration (and it must, since hash.insert(j, …) may have resized and thus realocated the content of the hashmap, giving data1 a new storage location in the hashmap). For completeness's sake, there are ways to get around that, but I don't recommend you do any of this:
Clone: let data1 = hash.get(&i).unwrap().clone() (if your vecs are short, this may actually be reasonable…)
As a way of making the cloning cheap, you could use a HashMap<usize, Rc<Vec<usize>>> instead (where you only need to clone the Rc, no the entire Vec)
If you ever need mutable references to both arguments of do_call, you could combine the Rc with a RefCell: Rc<RefCell<Vec<…>>>
If you need to overengineer it even more, you could replace the Rcs with references obtained from allocating in a bump allocator, e.g. bumpalo.
Since the keys to the hash table are the integers 0..100 you can use a Vec to perform these steps, temporarily splitting the Vec into 2 slices to allow the mutation on one side. If you need a HashMap for later computations, you can then create a HashMap from the Vec.
The following code compiles but panics because the j - 10 calculation underflows:
fn do_cal(a: &[usize], b: &[usize]) -> usize {
a.iter().sum::<usize>() + b.iter().sum::<usize>()
}
fn do_check(i: usize, j:usize) -> bool {
i/2 < j - 10
}
fn main() {
let size = 100;
let mut v: Vec<Option<Vec<usize>>> = vec![None; size];
for i in 0..size {
let (v1, v2) = v.split_at_mut(i + 1);
if v1[i].is_none() {
v1[i] = Some(vec![1,2,3]);
}
let data1 = v1[i].as_ref().unwrap();
for (j, item) in (i + 1..).zip(v2.iter_mut()) {
if do_check(i, j) {
break
}
if item.is_none() {
*item = Some(vec![1,2,3]);
}
let data2 = item.as_ref().unwrap();
let res = do_cal(data1, data2);
println!("res:{}", res);
}
}
}
Consider the following (contrived) way to increment x by 9.
fn main() {
let mut x = 0;
let mut f = || {
x += 4;
};
let _g = || {
f();
x += 5;
};
}
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> x.rs:6:12
|
3 | let mut f = || {
| -- first mutable borrow occurs here
4 | x += 4;
| - first borrow occurs due to use of `x` in closure
5 | };
6 | let _g = || {
| ^^ second mutable borrow occurs here
7 | f();
| - first borrow later captured here by closure
8 | x += 5;
| - second borrow occurs due to use of `x` in closure
error: aborting due to previous error
For more information about this error, try `rustc --explain E0499`.
So, it does not work. How to make an algorithm like the above that would modify a variable in a closure and call another closure from it that also modifies the variable?
In traditional languages it's easy. What to do in Rust?
The accepted answer is the most idiomatic approach, but there is also an alternative that is useful in situations when the additional argument doesn't work, for example when you need to pass the closure to third-party code that will call it without arguments. In that case you can use a Cell, a form of interior mutability:
use std::cell::Cell;
fn main() {
let x = Cell::new(0);
let f = || {
x.set(x.get() + 4);
};
let g = || {
f();
x.set(x.get() + 5);
};
f();
g();
assert_eq!(x.get(), 13);
}
By design, closures have to enclose external objects that are used in it upon creation, in our case closures have to borrow the external x object. So as compiler explained to you, upon creation of the closure f it mutably borrows x, and you can't borrow it once again when you create closure g.
In order to compile it you can't enclose any external object that you want to change. Instead you can directly pass the objects as a closure's argument (arguably it's even more readable). This way you describe that a closure accepts some object of some type, but you don't yet use/pass any actual object. This object will be borrowed only when you call the closure.
fn main() {
let mut x = 0;
let f = |local_x: &mut i32| { // we don't enclose `x`, so no borrow yet
*local_x += 4;
};
let _g = |local_x: &mut i32| { // we don't enclose `x`, so no borrow yet
f(local_x);
*local_x += 5;
};
_g(&mut x); // finally we borrow `x`, and this borrow will later move to `f`,
// so no simultaneous borrowing.
println!("{}", x); // 9
}
To expand on Alex Larionov's answer: you should think of a closure as a callable structure, anything you capture is set as a field of the structure, then implicitly dereferenced inside the function body. The way those fields are used is also what determines whether the closure is Fn, FnMut or FnOnce, basically whether the method would take &self, &mut self or self if it were written longhand.
Here
fn main() {
let mut x = 0;
let mut f = || {
x += 4;
};
// ...
}
essentially translates to:
struct F<'a> { x: &'a mut u32 }
impl F<'_> {
fn call(&mut self) {
*self.x += 4
}
}
fn main() {
let mut x = 0;
let mut f = F { x: &mut x };
// ...
}
from this, you can see that as soon as f is created, x is mutably borrowed, with all that implies.
And with this partial desugaring, we can see essentially the same error: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e129f19f25dc61de8a6f42cdca1f67b5
If we use the relevant unstable features on nightly we can get just a bit closer. That is pretty much what rustc does for us under the hood.
Here is the code:
fn test(){
let mut numbers = vec![2];
let f = || {
for _ in numbers.iter(){
}
false
};
while false {
let res = f();
if res {
numbers.push(10);
}
}
}
The error is:
|
15 | let f = || {
| -- immutable borrow occurs here
16 | for _ in numbers.iter(){
| ------- first borrow occurs due to use of `numbers` in closure
...
22 | let res = f();
| - immutable borrow later used here
23 | if res {
24 | numbers.push(10);
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
But if I change the while keyword to if, it can be compiled. How to fix this? I want to call the anonymous function in a loop.
We can simplify your example even more by replacing the closure by a simple immutable reference
let mut numbers = vec![2];
let r = &numbers;
while false {
println!("{:?}", r);
numbers.push(10);
}
Here we get this error:
error[E0502]: cannot borrow `numbers` as mutable because it is also borrowed as immutable
--> src/lib.rs:7:5
|
3 | let r = &numbers;
| -------- immutable borrow occurs here
...
6 | println!("{:?}", r); // use reference
| - immutable borrow later used here
7 | numbers.push(10);
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
And like in your example, replacing the while with if makes the error go away. Why?
You probably know about the important Rust rule: Aliasing nand mutability. It states that, at any given time, a value can either be borrowed immutably arbitrarily many times or mutably exactly once.
The statement numbers.push(10) borrows numbers mutably temporarily (just for the statement). But we also have r which is an immutable reference. In order for numbers.push(10) to work, the compiler has to make sure that no other borrow exists at that time. But there exists the reference r! This reference cannot exist at the same time as numbers.push(10) exists.
Let's see for the if case first:
let mut numbers = vec![2];
let r = &numbers; // <------+ (creation of r)
// |
if false { // |
println!("{:?}", r); // <------+ (last use of r)
numbers.push(10);
}
While the lexical scope means the variable r is only dropped at the end of the function, due to non-lexical lifetimes, the compiler can see that the last use of r is in the println line. Then the compiler can mark r as "dead" after this line. And this in turn means, that there is no other borrow in the line numbers.push(10) and everything works out fine.
And for the loop case? Let's imagine the loop iterating three times:
let mut numbers = vec![2];
let r = &numbers; // <------+ (creation of r)
// |
// First iteration // |
println!("{:?}", r); // |
numbers.push(10); // | <== oh oh!
// |
// Second iteration // |
println!("{:?}", r); // |
numbers.push(10); // |
// |
// Third iteration // |
println!("{:?}", r); // <------+ (last use of r)
numbers.push(10);
As can be seen here, the time in which r is active overlaps numbers.push(10) (except the last one). And as a result, the compiler will produce an error because this code violates the central Rust rule.
And the explanation is the same for your closure case: the closure borrows numbers immutably and f(); uses that closure. In the loop case, the compiler is not able to shrink the "alive time" of the closure enough to make sure it doesn't overlap the mutable borrow for push.
How to fix?
Well, you could pass numbers into the closure each time:
let mut numbers = vec![2];
let f = |numbers: &[i32]| {
for _ in numbers.iter(){
}
false
};
while false {
let res = f(&numbers);
if res {
numbers.push(10);
}
}
This works because now, numbers is borrowed immutably also just temporarily for the f(&numbers); statement.
You can also use a RefCell as the other answer suggested, but that should be a last resort.
It's not exactly sure what you're trying to accomplish, but one way to solve this, without changing your code too drastically, would be to use std::cell::RefCell (described in the std and in the book):
use std::cell::RefCell;
fn test(){
let numbers = RefCell::new(vec![2]);
let f = || {
for _ in numbers.borrow().iter(){
}
false
};
while false {
let res = f();
if res {
numbers.borrow_mut().push(10);
}
}
}
Here's a little bit tweaked demo, which actually does something:
use std::cell::RefCell;
fn main() {
test();
}
fn test() {
let numbers = RefCell::new(vec![0]);
let f = || {
for n in numbers.borrow().iter() {
println!("In closure: {}", n);
}
println!();
true
};
let mut i = 1;
while i <= 3 {
let res = f();
if res {
numbers.borrow_mut().push(i);
}
i += 1;
}
println!("End of test(): {:?}", numbers.borrow());
}
Output:
In closure: 0
In closure: 0
In closure: 1
In closure: 0
In closure: 1
In closure: 2
End of test(): [0, 1, 2, 3]
Rust Playground demo
I'm writing a Trie data structure in Rust to implement the Aho-Corasick algorithm. The TrieNode struct respresents a node and looks like this:
use std::collections::{HashMap, HashSet, VecDeque};
struct TrieNode {
next_ids: HashMap<char, usize>,
kw_indices: HashSet<usize>,
fail_id: Option<usize>,
}
I use the same strategy as a generational arena to implement the trie, where all the nodes are stored in one Vec and reference each other using their indices. When building the automaton after creating the all the nodes, I'm trying to get the following code work without using the clone() method:
fn build_ac_automaton(nodes: &mut Vec<TrieNode>) {
let mut q = VecDeque::new();
for &i in nodes[0].next_ids.values() {
q.push_back(i);
nodes[i].fail_id = Some(0);
}
// ...
}
but the borrow checker is not very happy about it:
error[E0502]: cannot borrow `*nodes` as mutable because it is also borrowed as immutable
|
| for &i in nodes[0].next_ids.values() {
| ----- - immutable borrow ends here
| |
| immutable borrow occurs here
| q.push_back(i);
| nodes[i].fail_id = Some(0);
| ^^^^^ mutable borrow occurs here
What is another way (if any) to achieve the above without using the costly clone() method?
Split the slice:
fn build_ac_automaton(nodes: &mut Vec<TrieNode>) {
let mut q = VecDeque::new();
let (first, rest) = nodes.split_first_mut();
for &i in first.next_ids.values() {
q.push_back(i);
if i == 0 {
first.fail_id = Some(0);
} else {
rest[i-1].fail_id = Some(0);
}
}
...
}
However it might be less costly to simply clone only the next_ids:
fn build_ac_automaton(nodes: &mut Vec<TrieNode>) {
let mut q = VecDeque::new();
let ids: Vec<_> = nodes[0].next_ids.values().cloned().collect();
for &i in ids {
q.push_back(i);
nodes[i].fail_id = Some(0);
}
...
}
I'm trying to implement a function that steps though two iterators at the same time, calling a function for each pair. This callback can control which of the iterators is advanced in each step by returning a (bool, bool) tuple. Since the iterators take a reference to a buffer in my use case, they can't implement the Iterator trait from the stdlib, but instead are used though a next_ref function, which is identical to Iterator::next, but takes an additional lifetime parameter.
// An iterator-like type, that returns references to itself
// in next_ref
struct RefIter {
value: u64
}
impl RefIter {
fn next_ref<'a>(&'a mut self) -> Option<&'a u64> {
self.value += 1;
Some(&self.value)
}
}
// Iterate over two RefIter simultaneously and call a callback
// for each pair. The callback returns a tuple of bools
// that indicate which iterators should be advanced.
fn each_zipped<F>(mut iter1: RefIter, mut iter2: RefIter, callback: F)
where F: Fn(&Option<&u64>, &Option<&u64>) -> (bool, bool)
{
let mut current1 = iter1.next_ref();
let mut current2 = iter2.next_ref();
loop {
let advance_flags = callback(¤t1, ¤t2);
match advance_flags {
(true, true) => {
current1 = iter1.next_ref();
current2 = iter2.next_ref();
},
(true, false) => {
current1 = iter1.next_ref();
},
(false, true) => {
current2 = iter1.next_ref();
},
(false, false) => {
return
}
}
}
}
fn main() {
let mut iter1 = RefIter { value: 3 };
let mut iter2 = RefIter { value: 4 };
each_zipped(iter1, iter2, |val1, val2| {
let val1 = *val1.unwrap();
let val2 = *val2.unwrap();
println!("{}, {}", val1, val2);
(val1 < 10, val2 < 10)
});
}
error[E0499]: cannot borrow `iter1` as mutable more than once at a time
--> src/main.rs:28:28
|
22 | let mut current1 = iter1.next_ref();
| ----- first mutable borrow occurs here
...
28 | current1 = iter1.next_ref();
| ^^^^^ second mutable borrow occurs here
...
42 | }
| - first borrow ends here
error[E0499]: cannot borrow `iter2` as mutable more than once at a time
--> src/main.rs:29:28
|
23 | let mut current2 = iter2.next_ref();
| ----- first mutable borrow occurs here
...
29 | current2 = iter2.next_ref();
| ^^^^^ second mutable borrow occurs here
...
42 | }
| - first borrow ends here
error[E0499]: cannot borrow `iter1` as mutable more than once at a time
--> src/main.rs:32:28
|
22 | let mut current1 = iter1.next_ref();
| ----- first mutable borrow occurs here
...
32 | current1 = iter1.next_ref();
| ^^^^^ second mutable borrow occurs here
...
42 | }
| - first borrow ends here
error[E0499]: cannot borrow `iter1` as mutable more than once at a time
--> src/main.rs:35:28
|
22 | let mut current1 = iter1.next_ref();
| ----- first mutable borrow occurs here
...
35 | current2 = iter1.next_ref();
| ^^^^^ second mutable borrow occurs here
...
42 | }
| - first borrow ends here
I understand why it complains, but can't find a way around it. I'd appreciate any help on the subject.
Link to this snippet in the playground.
Since the iterators take a reference to a buffer in my use case, they can't implement the Iterator trait from the stdlib, but instead are used though a next_ref function, which is identical to Iterator::next, but takes an additional lifetime parameter.
You are describing a streaming iterator. There is a crate for this, aptly called streaming_iterator. The documentation describes your problem (emphasis mine):
While the standard Iterator trait's functionality is based off of
the next method, StreamingIterator's functionality is based off of
a pair of methods: advance and get. This essentially splits the
logic of next in half (in fact, StreamingIterator's next method
does nothing but call advance followed by get).
This is required because of Rust's lexical handling of borrows (more
specifically a lack of single entry, multiple exit borrows). If
StreamingIterator was defined like Iterator with just a required
next method, operations like filter would be impossible to define.
The crate does not currently have a zip function, and certainly not the variant you have described. However, it's easy enough to implement:
extern crate streaming_iterator;
use streaming_iterator::StreamingIterator;
fn each_zipped<A, B, F>(mut iter1: A, mut iter2: B, callback: F)
where
A: StreamingIterator,
B: StreamingIterator,
F: for<'a> Fn(Option<&'a A::Item>, Option<&'a B::Item>) -> (bool, bool),
{
iter1.advance();
iter2.advance();
loop {
let advance_flags = callback(iter1.get(), iter2.get());
match advance_flags {
(true, true) => {
iter1.advance();
iter2.advance();
}
(true, false) => {
iter1.advance();
}
(false, true) => {
iter1.advance();
}
(false, false) => return,
}
}
}
struct RefIter {
value: u64
}
impl StreamingIterator for RefIter {
type Item = u64;
fn advance(&mut self) {
self.value += 1;
}
fn get(&self) -> Option<&Self::Item> {
Some(&self.value)
}
}
fn main() {
let iter1 = RefIter { value: 3 };
let iter2 = RefIter { value: 4 };
each_zipped(iter1, iter2, |val1, val2| {
let val1 = *val1.unwrap();
let val2 = *val2.unwrap();
println!("{}, {}", val1, val2);
(val1 < 10, val2 < 10)
});
}
The issue with this code is that RefIter is being used in two ways, which are fundamentally at odds with one another:
Callers of next_ref recieve a reference to the stored value, which is tied to the lifetime of RefIter
RefIter's value needs to be mutable, so that it can be incremented on each call
This perfectly describes mutable aliasing (you're trying to modify 'value' while a reference to it is being held) - something which Rust is explicitly designed to prevent.
In order to make each_zipped work, you'll need to modify RefIter to avoid handing out references to data that you wish to mutate.
I've implemented one possibility below using a combination of RefCell and Rc:
use std::cell::RefCell;
use std::rc::Rc;
// An iterator-like type, that returns references to itself
// in next_ref
struct RefIter {
value: RefCell<Rc<u64>>
}
impl RefIter {
fn next_ref(&self) -> Option<Rc<u64>> {
let new_val = Rc::new(**self.value.borrow() + 1);
*self.value.borrow_mut() = new_val;
Some(Rc::clone(&*self.value.borrow()))
}
}
// Iterate over two RefIter simultaniously and call a callback
// for each pair. The callback returns a tuple of bools
// that indicate which iterators should be advanced.
fn each_zipped<F>(iter1: RefIter, iter2: RefIter, callback: F)
where F: Fn(&Option<Rc<u64>>, &Option<Rc<u64>>) -> (bool, bool)
{
let mut current1 = iter1.next_ref();
let mut current2 = iter2.next_ref();
loop {
let advance_flags = callback(¤t1, ¤t2);
match advance_flags {
(true, true) => {
current1 = iter1.next_ref();
current2 = iter2.next_ref();
},
(true, false) => {
current1 = iter1.next_ref();
},
(false, true) => {
current2 = iter1.next_ref();
},
(false, false) => {
return
}
}
}
}
fn main() {
let iter1 = RefIter { value: RefCell::new(Rc::new(3)) };
let iter2 = RefIter { value: RefCell::new(Rc::new(4)) };
each_zipped(iter1, iter2, |val1, val2| {
// We can't use unwrap() directly, since we're only passed a reference to an Option
let val1 = **val1.iter().next().unwrap();
let val2 = **val2.iter().next().unwrap();
println!("{}, {}", val1, val2);
(val1 < 10, val2 < 10)
});
}
This version of RefIter hands out Rcs to consumers, instead of references. This avoids the issue of mutable aliasing - updating value is done by placing
a new Rc into the outer RefCell. A side effect of this is that consumers are able to hold onto an 'old' reference to the buffer (through the returned Rc), even after RefIter has advanced.