How do I modify a borrowed struct's field in Rust? - rust

I have a &mut reference to a struct. I want to reassign a field of the referenced struct, but I only get cannot assign to current_node.parameter because it is borrowed.
I have also tried let ref mut in the current_node declaration, but the same issue happened.
pub fn create_ars_tree() {
let mut top_level_node = NodeItem {
key: StringOrNodeItems::Text(String::new()),
parameter: StringOrNodeItems::Text(String::new()),
parent_item: None,
};
let mut current_node = &mut top_level_node; //Reference to the currently edited node
let mut current_part = &current_node.key; //Reference to the currently edited string
for current_char in "abcdef".chars() {
if current_char == '{' {
//Handle new opening bracket
match current_part {
StringOrNodeItems::Text(text) => {
current_node.key = StringOrNodeItems::Keys(vec![
NodeItem {
key: StringOrNodeItems::Text(text.to_string()),
parameter: StringOrNodeItems::Text(String::new()),
parent_item: Some(current_node)
//parent_item: None
}
]);
},
StringOrNodeItems::Keys(keys) => {
unimplemented!();
}
}
}
}
}
#[derive(Debug)]
pub struct NodeItem<'a> {
key: StringOrNodeItems<'a>,
parameter: StringOrNodeItems<'a>,
parent_item: Option<&'a NodeItem<'a>>,
}
#[derive(Debug)]
enum StringOrNodeItems<'a> {
Text(String),
Keys(Vec<NodeItem<'a>>),
}
Error:
error[E0506]: cannot assign to `current_node.key` because it is borrowed
--> src/lib.rs:14:6
|
8 | let mut current_part = &current_node.key; //Reference to the currently edited string
| ----------------- borrow of `current_node.key` occurs here
...
12 | match current_part {
| ------------ borrow later used here
13 | StringOrNodeItems::Text(text) => {
14 | current_node.key = StringOrNodeItems::Keys(vec![
| ^^^^^^^^^^^^^^^^ assignment to borrowed `current_node.key` occurs here
Playground

I have figured it out. The issue is that I am trying to assign current_node inside a block borrowing that same variable. If you replace Some(current_node) with None it compiles

Related

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

Create vector of trait objects

I am trying to create a vector of trait objects but I'm getting a type mismatch. I also tried using .map() instead of a for loop but had the same problem. This is a minimal version of my real code, I realise this example doesn't require the use of trait objects but my real code does since there will be types other than Link in the List, which also implement Speak. How can I create a Vec with the correct type so I can pass it to trait_objects?
use std::fs;
fn main() {
// let links = fs::read_dir("my_dir").unwrap();
// let links: Vec<Box<dyn Speak>> = links
// .map(|file| {
// let myfile = file.unwrap();
// let href = myfile.path().to_str().unwrap();
// Box::new(Link { attr: href })
// })
// .collect();
let links = Vec::new();
for entry in fs::read_dir("my_dir").unwrap() {
let myfile = entry.unwrap();
let href = myfile.path().to_str().unwrap();
links.push(Box::new(Link { attr: href }));
}
let link_objects = ListOfTraitObjects {
trait_objects: links,
};
for link in link_objects.trait_objects.iter() {
println!("{}", link.speak());
}
}
trait Speak {
fn speak(&self) -> String;
}
struct ListOfTraitObjects {
trait_objects: Vec<Box<dyn Speak>>,
}
struct Link<'a> {
attr: &'a str,
}
impl Speak for Link<'_> {
fn speak(&self) -> String {
self.attr.to_string()
}
}
There are several issues with your code. The first is that you're creating a Vec<Box<Link>> instead of a Vec<Box<Speak>>. By default Box::new (foo) creates a box of the same type as foo. If you want a box of some trait implemented by foo, you need to be explicit:
links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
Playground
However this gives two new errors:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:7:20
|
7 | let href = myfile.path().to_str().unwrap();
| ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
8 | links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
| ----------------------------- cast requires that borrow lasts for `'static`
error[E0596]: cannot borrow `links` as mutable, as it is not declared as mutable
--> src/lib.rs:8:9
|
4 | let links = Vec::new();
| ----- help: consider changing this to be mutable: `mut links`
...
8 | links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
The first error is because your Link struct borrows a string from entry, but entry only lives as long as the current loop iteration. Even though the error states that the cast requires a 'static lifetime, you would get a similar error if you were simply trying to build a Vec<Link> without casting (playground). You need to change the definition of your Link struct to contain an owned string:
struct Link {
attr: String,
}
impl Speak for Link {
fn speak(&self) -> String {
self.attr.clone()
}
}
The second error is easier and can be fixed simply by following the compiler suggestion and replacing let links = … with let mut links = ….
Full working example:
use std::fs;
fn main() {
let mut links = Vec::new();
for entry in fs::read_dir("my_dir").unwrap() {
let myfile = entry.unwrap();
let href = myfile.path().to_str().unwrap().to_string();
links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
}
let link_objects = ListOfTraitObjects {
trait_objects: links,
};
for link in link_objects.trait_objects.iter() {
println!("{}", link.speak());
}
}
trait Speak {
fn speak(&self) -> String;
}
struct ListOfTraitObjects {
trait_objects: Vec<Box<dyn Speak>>,
}
struct Link {
attr: String,
}
impl Speak for Link {
fn speak(&self) -> String {
self.attr.clone()
}
}
Playground
The same fixes can be applied to your iterator-based solution:
let links = fs::read_dir("my_dir").unwrap();
let links: Vec<_> = links
.map(|file| {
let myfile = file.unwrap();
let href = myfile.path().to_str().unwrap().to_string();
Box::new(Link { attr: href }) as Box<dyn Speak>
})
.collect();
Playground

Iterating through a recursive structure using mutable references and returning the last valid reference

I'm trying to recurse down a structure of nodes, modifying them, and then returning the last Node that I get to. I solved the problems with mutable references in the loop using an example in the non-lexical lifetimes RFC. If I try to return the mutable reference to the last Node, I get a use of moved value error:
#[derive(Debug)]
struct Node {
children: Vec<Node>,
}
impl Node {
fn new(children: Vec<Self>) -> Self {
Self { children }
}
fn get_last(&mut self) -> Option<&mut Node> {
self.children.last_mut()
}
}
fn main() {
let mut root = Node::new(vec![Node::new(vec![])]);
let current = &mut root;
println!("Final: {:?}", get_last(current));
}
fn get_last(mut current: &mut Node) -> &mut Node {
loop {
let temp = current;
println!("{:?}", temp);
match temp.get_last() {
Some(child) => { current = child },
None => break,
}
}
current
}
Gives this error
error[E0382]: use of moved value: `*current`
--> test.rs:51:5
|
40 | let temp = current;
| ---- value moved here
...
51 | current
| ^^^^^^^ value used here after move
|
= note: move occurs because `current` has type `&mut Node`, which does not implement the `Copy` trait
If I return the temporary value instead of breaking, I get the error cannot borrow as mutable more than once.
fn get_last(mut current: &mut Node) -> &mut Node {
loop {
let temp = current;
println!("{:?}", temp);
match temp.get_last() {
Some(child) => { current = child },
None => return temp,
}
}
}
error[E0499]: cannot borrow `*temp` as mutable more than once at a time
--> test.rs:47:28
|
43 | match temp.get_last() {
| ---- first mutable borrow occurs here
...
47 | None => return temp,
| ^^^^ second mutable borrow occurs here
48 | }
49 | }
| - first borrow ends here
How can I iterate through the structure with mutable references and return the last Node? I've searched, but I haven't found any solutions for this specific problem.
I can't use Obtaining a mutable reference by iterating a recursive structure because it gives me a borrowing more than once error:
fn get_last(mut current: &mut Node) -> &mut Node {
loop {
let temp = current;
println!("{:?}", temp);
match temp.get_last() {
Some(child) => current = child,
None => current = temp,
}
}
current
}
This is indeed different from Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time. If we look at the answer there, modified a bit, we can see that it matches on a value and is able to return the value that was matched on in the terminal case. That is, the return value is an Option:
fn back(&mut self) -> &mut Option<Box<Node>> {
let mut anchor = &mut self.root;
loop {
match {anchor} {
&mut Some(ref mut node) => anchor = &mut node.next,
other => return other, // transferred ownership to here
}
}
}
Your case is complicated by two aspects:
The lack of non-lexical lifetimes.
The fact that you want to take a mutable reference and "give it up" in one case (there are children) and not in the other (no children). This is conceptually the same as this:
fn maybe_identity<T>(_: T) -> Option<T> { None }
fn main() {
let name = String::from("vivian");
match maybe_identity(name) {
Some(x) => println!("{}", x),
None => println!("{}", name),
}
}
The compiler cannot tell that the None case could (very theoretically) continue to use name.
The straight-forward solution is to encode this "get it back" action explicitly. We create an enum that returns the &mut self in the case of no children, a helper method that returns that enum, and rewrite the primary method to use the helper:
enum LastOrNot<'a> {
Last(&'a mut Node),
NotLast(&'a mut Node),
}
impl Node {
fn get_last_or_self(&mut self) -> LastOrNot<'_> {
match self.children.is_empty() {
false => LastOrNot::Last(self.children.last_mut().unwrap()),
true => LastOrNot::NotLast(self),
}
}
fn get_last(mut current: &mut Node) -> &mut Node {
loop {
match { current }.get_last_or_self() {
LastOrNot::Last(child) => current = child,
LastOrNot::NotLast(end) => return end,
}
}
}
}
Note that we are using all of the techniques exposed in both Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in? and Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time.
With an in-progress reimplementation of NLL, we can simplify get_last_or_self a bit to avoid the boolean:
fn get_last_or_self(&mut self) -> LastOrNot<'_> {
match self.children.last_mut() {
Some(l) => LastOrNot::Last(l),
None => LastOrNot::NotLast(self),
}
}
The final version of Polonius should allow reducing the entire problem to a very simple form:
fn get_last(mut current: &mut Node) -> &mut Node {
while let Some(child) = current.get_last() {
current = child;
}
current
}
See also:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time

Swapping values between two hashmaps

Edit Note: This code now compile see What are non-lexical lifetimes?.
I have two HashMaps and want to swap a value between them under certain conditions. If the key does not exist in the second HashMap, it should be inserted. I do not want to clone the value, since that is too expensive.
The (simplified) critical code that is not working is as follows:
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::mem;
#[derive(Debug)]
struct ExpensiveStruct {
replace: bool,
// imagine a lot of heap data here
}
fn main() {
let mut hm : HashMap<usize, ExpensiveStruct> = HashMap::new();
let mut hm1 : HashMap<usize, ExpensiveStruct> = HashMap::new();
let dummy = ExpensiveStruct { replace: false };
hm.insert(1, ExpensiveStruct { replace: true});
hm1.insert(1, ExpensiveStruct { replace: true});
match hm1.get_mut(&1) {
Some(ref mut x) =>
match hm.entry(1) {
Entry::Occupied(mut y) => { if y.get().replace {
mem::swap(x, &mut y.get_mut());
}
},
Entry::Vacant(y) => { y.insert(mem::replace(x, dummy)); }
},
None => {}
}
println!("{:?}", hm);
}
(On the Rust Playground)
I get the error:
error[E0597]: `y` does not live long enough
--> src/main.rs:28:9
|
23 | mem::swap(x, &mut y.get_mut());
| - borrow occurs here
...
28 | },
| ^ `y` dropped here while still borrowed
29 | None => {}
30 | }
| - borrowed value needs to live until here
I am really confused about this borrow problem and I do not see a way to fix it. If I replace the Entry by a match hm.get_mut(1), I cannot insert in the None case, since the matching mutably borrows the HashMap.
You're giving references to references where you should be giving references.
&mut y.get_mut()
for instance is
&mut &mut ExpensiveStruct
and you're having a simular issue with
match hm1.get_mut(&1) {
Some(ref mut x) =>
Your code works as expected when the types are trimmed down to &mut ExpensiveStruct:
match hm1.get_mut(&1) {
Some(x) => match hm.entry(1) {
Entry::Occupied(mut y) => if y.get().replace {
mem::swap(x, y.get_mut());
(On the Playground)
Note that the ref mut is removed, because hm1.get_mut(&1) already returns an Option for a mutable reference, and the &mut is removed because y.get_mut() already returns a reference.

Multiple mutable borrows during a depth-first tree search

How would one restructure this function that does a depth-first search and returns the parent of the matching node?
I know that variations of this problem have come up very often (e.g. Multiple mutable borrows when generating a tree structure with a recursive function in Rust, Mut borrow not ending where expected), but I still can’t figure out how to modify it to work. I have tried variations using slices, std::mem::drop, and adding lifetime parameters where 'a: 'b but I still haven’t figured out write it without conditionally mutably borrowing a variable in one branch and then using the variable in another branch.
#[derive(Clone, Debug)]
struct TreeNode {
id: i32,
children: Vec<TreeNode>,
}
// Returns a mutable reference to the parent of the node that matches the given id.
fn find_parent_mut<'a>(root: &'a mut TreeNode, id: i32) -> Option<&'a mut TreeNode> {
for child in root.children.iter_mut() {
if child.id == id {
return Some(root);
} else {
let descendent_result = find_parent_mut(child, id);
if descendent_result.is_some() {
return descendent_result;
}
}
}
None
}
fn main() {
let mut tree = TreeNode {
id: 1,
children: vec![TreeNode {
id: 2,
children: vec![TreeNode {
id: 3,
children: vec![],
}],
}],
};
let a: Option<&mut TreeNode> = find_parent_mut(&mut tree, 3);
assert_eq!(a.unwrap().id, 2);
}
error[E0499]: cannot borrow `*root` as mutable more than once at a time
--> src/main.rs:11:25
|
9 | for child in root.children.iter_mut() {
| ------------- first mutable borrow occurs here
10 | if child.id == id {
11 | return Some(root);
| ^^^^ second mutable borrow occurs here
...
20 | }
| - first borrow ends here
Here it is with #huon’s suggestions and continued compiler errors:
fn find_parent_mut<'a>(root: &'a mut TreeNode, id: i32) -> Option<&'a mut TreeNode> {
for child in root.children {
if child.id == id {
return Some(root);
}
}
for i in 0..root.children.len() {
let child: &'a mut TreeNode = &mut root.children[i];
let descendent_result = find_parent_mut(child, id);
if descendent_result.is_some() {
return descendent_result;
}
}
None
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:9:18
|
9 | for child in root.children {
| ^^^^ cannot move out of borrowed content
error[E0499]: cannot borrow `root.children` as mutable more than once at a time
--> src/main.rs:15:44
|
15 | let child: &'a mut TreeNode = &mut root.children[i];
| ^^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first mutable borrow occurs here
...
22 | }
| - first borrow ends here
I managed to have it working this way:
fn find_parent_mut<'a>(root: &'a mut TreeNode, id: i32)
-> Option<&'a mut TreeNode> {
if root.children.iter().any(|child| {child.id == id}) {
return Some(root);
}
for child in &mut root.children {
match find_parent_mut(child, id) {
Some(result) => return Some(result),
None => {}
}
}
None
}
First in you second attempt, you wrote for child in root.children instead of the for child in &mut root.children (note the missing &mut),which caused root.children to be consumed by the loop instead of just iterated over, hence the cannot move out of borrowed content error.
I also folded it in a more iterator-ich way, using the any(..) function.
For the second loop, I'm not exactly sure what was going on, by apparently binding the references to variables was confusing the borrow-checker. I removed any temporary variable, and now it compiles.
One can do this in a single pass by doing the search, recording some data from it, and then computing the return value efficiently outside the loop:
let mut found = Err(());
for (i, child) in root.children.iter_mut().enumerate() {
if child.id == id {
found = Ok(None);
break;
} else find_parent_mut(child, id).is_some() {
found = Ok(Some(i));
break;
}
}
match found {
Ok(Some(i)) => Some(&mut root.children[i]),
Ok(None) => Some(root),
Err(()) => None,
}
This avoids the issues caused by conditionally returning mutable variables (which is the problems you and my answer below were meeting) by completely avoiding returns inside the inner loop.
Old/incorrect answer:
I'm unable to test my suggestions right now, but I believe the best way to solve this is to return root outside the loop.
for child in &mut root.children {
if child.id == id {
found = true;
break
} ...
}
if found {
Some(root)
} else {
None
}
This (hopefully) ensures that root isn't borrowed via children when it is being manipulated.
However I suspect the early return inside the main loop may interfere, in which case one might just have to fall back to integers and indexing:
for i in 0..root.children.len() {
if root.children[i].id == id {
return Some(root)
...
}

Resources