Understanding clones borrow - rust

I'm fairly new to rust, and still learning the rust ownership model. I'm working on a piece of code where I hold a reference to a point in the data structure. I want to store multiple copies of this data structure, where on each copy the reference point hold different values. I (tried to) solve this by creating a mutable reference to the point inside the data structure, and after each update of the reference create a clone of the original data structure.
I was able to create this simple example that is analogue to what i'm trying to do and produces the same error.
fn main() {
let mut v = vec![1, 1, 1];
let mut c = Vec::new();
for i in &mut v {
*i += 1;
c.push(v.clone());
}
println!("{:?}", v);
}
which produces the following error
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/main.rs:107:16
|
105 | for i in &mut v {
| ------
| |
| mutable borrow occurs here
| mutable borrow later used here
106 | *i += 1;
107 | c.push(v.clone());
| ^ immutable borrow occurs here
With some help of the handy rust book i was able to interpret the error message. I believe this tells me that I cannot have both a mutable, and an immutable reference that are alive at the same time. What is (or is there) an rust-idiomatic method of iteratively creating duplicates of a data structure and updating a reference within said data structure?
Edit:
The example above might be too minified and not highlight the actual problem I'm having. What would be the rust-idiomatic way to write something like the example below.
#[derive(Clone, Debug)]
enum Tree {
Leaf,
Node { l: Box<Tree>, r: Box<Tree>, },
}
fn main() {
let mut tree = Tree::Node {
l: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }),
r: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }),
};
let augmenting_trees = vec![
Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), },
Tree::Node { l: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }), r: Box::new(Tree::Leaf), },
Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }), },
];
let mut trees: Vec<Tree> = Vec::new();
let leaf = find_some_leaf_in_tree(&mut tree);
for augmenting_tree in augmenting_trees {
*leaf = augmenting_tree;
trees.push(tree.clone());
}
println!("trees: {:?}", trees);
}
fn find_some_leaf_in_tree<'a>(tree: &'a mut Tree) -> &'a mut Tree {
match tree {
Tree::Leaf => tree,
Tree::Node { l, .. } => find_some_leaf_in_tree(l),
}
}

What is (or is there) an rust-idiomatic method of iteratively creating duplicates of a data structure and updating a reference within said data structure?
The general answer is “don't use a reference for the purpose you're trying to use a reference”. In this case, you have a vector, so use indices instead of references:
fn main() {
let mut v = vec![1, 1, 1];
let mut c = Vec::new();
for i in 0..v.len() {
v[i] += 1;
c.push(v.clone());
}
dbg!(v, c);
}
Note that this doesn't mean you can't use references at all. For example, the code could be written in terms of a mutable reference to v instead:
fn modify_and_snapshot(v: &mut Vec<u32>) -> Vec<Vec<u32>> {
let mut c = Vec::new();
for i in 0..v.len() {
v[i] += 1;
c.push(v.clone());
}
c
}
fn main() {
let mut v = vec![1, 1, 1];
let c = modify_and_snapshot(&mut v);
dbg!(v, c);
}
The necessary condition is that when you want to snapshot v, you don't have a mutable reference to less than all of v — you can own the whole vector or you can have a mutable reference to the whole vector, but you can't do anything with the whole of the vector while a mutable reference to part of it exists.

Related

Cannot borrow value from a hashmap as mutable because it is also borrowed as immutable

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);
}
}
}

Hashmap multiple mutable borrow issue after reference drop

I am trying to pass around a HashMap which stores values through a set of nested enums/structs. The problem of multiple mutability happens during iteration, even all references should be dropped.
The general idea is to have a vector of values, iterate through them and simplify them, keeping track of them within the HashMap. There are two stages of simplification.
The general flow looks something like
run(Vec<ComplexVal>)
-for each val->
val.fix_complex(holder)
-for each `smp` SimpleVal in val->
basicval = Simplifier::step(smp, holder)
holder.insert("name", basicval)
But the problem is that the holder is borrowed mutably in each stage, and there isn't supposed to be any reference from the ComplexVal to the holder and since the borrowchecker doesn't like multiple borrows, it fails.
Full playground snippet: here
It happens in this snippet:
pub fn run(&mut self, mut vals: Vec<ComplexVal>) {
let mut holder = Holder{hold:HashMap::new()};
// .. setup holder code omitted
let len = vals.len();
for _ in 0..len {
let mut val = vals.remove(0); // remove from vec, should drop after running
println!("Running {:?}", val);
match val {
ComplexVal::Cmplx1(mut c) => {
c.fix_complex(&mut holder)
},
//... more cases of different types of values omitted for simplicity
}
// val *should* be dropped here, and therefore the mutable borrow of holder?
}
println!("Holder: {:?}", holder);
}
}
The only thing I can think of is that it somehow is related to the BasicVal::Ref(&BasicVal) value when created.
I need to return a reference of type &BasicVal so I can't use a regular fn() -> &BasicVal as the reference would be dangling, so I pass a ret value which is to be modified and used as the storage for the return value.
I have also tried just returning the enum BasicVal::Ref(&BasicVal), but run into the same mutability issues.
The example below is a much more simple version which (sort of) demonstrates the same error, just thought I'd include this context in case someone has another idea on how to implement this which wouldn't have these issues
Code (edited)
Updated playground link
Edit: I made a mistake in not needing the lifetimes of both holder and ret to explicitly be the same, so I have made an updated example for it
use std::borrow::BorrowMut;
///////////////////////////////
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
#[derive(Debug)]
enum BasicVal<'a> {
Ref(&'a BasicVal<'a>),
Val1(BasicStruct),
}
#[derive(Debug)]
struct Holder<'b> {
hold: HashMap<String, RefCell<BasicVal<'b>>>,
}
#[derive(Debug)]
struct BasicStruct {
val: i32,
}
impl<'a> BasicVal<'a> {
pub fn empty() -> Self { BasicVal::Val1(BasicStruct { val: 0 }) }
}
// must match sig of modify_val_ref
fn modify_val<'f>(holder: &'f mut Holder<'f>, mut ret: RefMut<BasicVal<'f>>) {
*ret = BasicVal::Val1(BasicStruct { val: 5 });
}
// must match sig of modify_val
fn modify_val_ref<'f>(holder: &'f mut Holder<'f>, mut ret: RefMut<BasicVal<'f>>) {
ret = holder.hold.get("reference_val").unwrap().borrow_mut();
}
fn do_modify<'f>(holder: &'f mut Holder<'f>) {
let mut v = RefCell::new(BasicVal::empty());
println!("Original {:?}", v);
modify_val(holder, v.borrow_mut());
holder.hold.insert("Data".to_string(), v);
println!("Modified {:?}", holder.hold.get("Data"));
}
pub fn test_dropborrow() {
let mut holder = Holder { hold: HashMap::new() };
holder.hold.insert(
"reference_val".to_string(),
RefCell::new(BasicVal::Val1(BasicStruct { val: 8 })),
);
do_modify(&mut holder);
}
pub fn main() {
test_dropborrow();
}
Edit: Using just the holder for a temp return value gives me a multiple mutable borrow issue, so that workaround doesn't work. I have also tried it with a RefCell with the same issue.
fn modify_val<'f>(holder: &'f mut Holder<'f>) {
holder.hold.insert("$return".to_string(), BasicVal::Val1(BasicStruct{val: 5}));
}
fn do_modify<'f>(holder: &'f mut Holder<'f>) {
modify_val(holder);
let mut v = holder.hold.remove("$return").unwrap();
holder.hold.insert("Data".to_string(), v);
println!("Modified {:?}", v);
}
Error:
935 | fn do_modify<'f>(holder: &'f mut Holder<'f>) {
| -- lifetime `'f` defined here
936 |
937 | modify_val(holder);
| ------------------
| | |
| | first mutable borrow occurs here
| argument requires that `*holder` is borrowed for `'f`
938 | let mut v = holder.hold.remove("$return").unwrap();
| ^^^^^^^^^^^ second mutable borrow occurs here
Any help is greatly appreciated!!!
Figured it out, essentially the BasicVal<'a> was causing Holder to mutably borrow itself in successive iterations of the loop, so removing the lifetime was pretty much the only solution

Mutate a field of a Vec's element while looping over a field of another element in the same Vec

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);
}
...
}

How to access a vector multiple times within an 'Option'?

How to access a vector within an option without Rust moving it on the first access?
fn maybe_push(v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
if let Some(v) = v_option {
for i in 0..10 {
v.push(i);
c += i;
}
} else {
for i in 0..10 {
c += i;
}
}
// second access, fails
if let Some(v) = v_option {
for i in 10..20 {
v.push(i);
c += i;
}
} else {
for i in 10..20 {
c += i;
}
}
return c;
}
fn main() {
let mut v: Vec<usize> = vec![];
println!("{}", maybe_push(Some(&mut v)));
println!("{}", maybe_push(None));
println!("{:?}", v);
}
This gives the error:
error[E0382]: use of partially moved value: `v_option`
--> src/main.rs:16:22
|
4 | if let Some(v) = v_option {
| - value moved here
...
16 | if let Some(v) = v_option {
| ^^^^^^^^ value used here after move
Using if let Some(ref mut v) = v_option { which has been suggested fails too:
error: cannot borrow immutable anonymous field `(v_option:std::prelude::v1::Some).0` as mutable
--> src/main.rs:4:21
|
4 | if let Some(ref mut v) = v_option {
| ^^^^^^^^^
error: cannot borrow immutable anonymous field `(v_option:std::prelude::v1::Some).0` as mutable
--> src/main.rs:17:21
|
17 | if let Some(ref mut v) = v_option {
| ^^^^^^^^^
Matching by value moves the value into the pattern variables. Moving makes the original value unusable, except for the very simple objects that implement the Copy trait, such as numbers. Unlike pointers in C, mutable references are not copyable, which can be seen in the following example that doesn't compile either:
let mut v = vec![1, 2, 3];
let rv = &mut v; // mutable reference to v
{
// move rv to r1, r1 now becomes the sole mutable reference to v
let r1 = rv;
r1.push(4);
}
{
let r2 = rv; // error: rv was already moved to r1
r2.push(5);
}
Rust rejects the above because it enforces the general rule prohibiting multiple mutable references to an object. Despite this particular snippet being safe, allowing multiple mutable references to the same object at the same time would make it easy to write the kind of unsafe programs that Rust is explicitly designed to prevent, e.g. those that contain data races in multithreaded code, or those that access data through an invalidated iterator. Thus the assignment let r1 = rv can only move the rv reference to r1, disallowing the let r2 = rv statement which now refers to moved variable rv.
To fix the code, we must create separate references to the reference. This will create two distinct mutable references to the original reference rather than moving the original mutable reference into an inner scope:
let mut v = vec![1, 2, 3];
let mut rv = &mut v;
{
// rr1 is a *new* mutable reference to rv - no move is performed
let rr1 = &mut rv;
rr1.push(4);
}
{
// rr2 is a *separate* new mutable reference to rv - also no move
let rr2 = &mut rv;
rr2.push(5);
}
The syntax of push invocation is the same with r1.push and rr1.push because Rust's . operator will automatically dereference any number of references.
To return to the example from the question, the reference to Vec<usize> in the Option is like the v reference above, and matching it using the Some(v) pattern moves the reference into the v pattern variable.
To fix it, the pattern must be changed as in the above example, to specify a variable that refers to the value which is itself a reference. This is achieved using the if let Some(ref mut v) syntax. As above, where the rv declaration had to be changed to mutable, this fix also requires the Option to be mutable. With those two changes, the code compiles:
fn maybe_push(mut v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
if let Some(ref mut v) = v_option {
for i in 0..10 {
v.push(i);
c += i;
}
} else {
for i in 0..10 {
c += i;
}
}
if let Some(ref mut v) = v_option {
for i in 10..20 {
v.push(i);
c += i;
}
} else {
for i in 10..20 {
c += i;
}
}
return c;
}
fn main() {
let mut v: Vec<usize> = vec![];
println!("{}", maybe_push(Some(&mut v)));
println!("{}", maybe_push(None));
println!("{:?}", v);
}
Another possibility is to use the as_mut() method to return the option content as a mutable reference to the previous content. This is conceptually equivalent to the change from let r1 = rv to let rr1 = &mut rv in the first snippet, and would allow the use of if let Some(v) pattern, where v would still be a reference to mutable reference to the vector. This also requires that v_option is declared as mutable.

Why can't I make a reference to memory inside "if"?

I could make a copy of this vector, but that will take time and memory.
I could write another println, but this is just an example — instead of println there may be several loops — and it will take space and complicate the code. I could perform the conversion in main and write two versions of the function call, but changing the reference is much easier.
fn foo(mut a: &Vec<i32>) {
let mut c: Vec<i32>;
if a[0] == 0 {
c = vec![1; 3];
a = &c;
}
println!("{:?}", a);
}
fn main() {
let a: Vec<i32> = vec![0; 3];
foo(&a);
}
Error:
main.rs:9:14: 9:15 error: `c` does not live long enough
main.rs:9 a = &c;
^
The rules of lifetime in rust are quite (very) strict: if you have a reference to an object, this object must live longer than the reference, in both direction.
This means the reference must be created after the object.
In your case, a exists before c, so the assignment a = &c is invalid. A simple fix can be to create a copy of the reference after c is created and work on this copy:
fn foo(vec_ref: &Vec<i32>){
let mut c: Vec<i32>;
let mut a = vec_ref
if a[0] == 0 {
c = vec![1; 3];
a = &c;
}
println!("{:?}",a);
}
or in a more rusty way:
fn foo(vec_ref: &Vec<i32>){
let mut c: Vec<i32>;
let a = if vec_ref[0] == 0 {
c = vec![1; 3];
&c
} else {
vec_ref
};
println!("{:?}",a);
}

Resources