Borrow inside a loop - rust

I'm trying to learn Rust after many years of C++. I have a situation where the compiler is complaining about a borrow, and it doesn't seem to matter whether it is mutable or immutable. I don't seem to be able to use self as a parameter inside a loop that start with: for item in self.func.drain(..).I've tried calling appropriate() as a function:
Self::appropriate(&self,&item,index)
and I have tried it as a method:
self.appropriate(&item,index)
but I get the same message in either case:
The function or method appropriate() is intended imply examine the relationship among its parameters and return a bool without modifying anything. How can I call either a function or method on self without violating borrowing rules?This program is a learning exercise from exercism.org and doesn't include a main() so it won't run but should almost compile except for the error in question. Here's the code I have:
use std::collections::HashMap;
pub type Value = i32;
pub type Result = std::result::Result<(), Error>;
pub struct Forth {
v: Vec<Value>,
f: HashMap<String,usize>,
s: Vec<Vec<String>>,
func: Vec<String>
}
#[derive(Debug, PartialEq)]
pub enum Error {
DivisionByZero,
StackUnderflow,
UnknownWord,
InvalidWord,
}
impl Forth {
pub fn new() -> Forth {
let mut temp: Vec<Vec<String>> = Vec::new();
temp.push(Vec::new());
Forth{v: Vec::<Value>::new(), f: HashMap::new(), s: temp, func: Vec::new()}
}
pub fn stack(&self) -> &[Value] {
&self.v
}
pub fn eval(&mut self, input: &str) -> Result {
self.v.clear();
self.s[0].clear();
let mut count = 0;
{
let temp: Vec<&str> = input.split(' ').collect();
let n = temp.len() as i32;
for x in 0..n as usize {
self.s[0].push(String::from(temp[x]));
}
}
let mut collecting = false;
let mut xlist: Vec<(usize,usize)> = Vec::new();
let mut sx: usize = 0;
let mut z: i32 = -1;
let mut x: usize;
let mut n: usize = self.s[0].len();
loop {
count += 1;
if count > 20 {break;}
z += 1;
x = z as usize;
if x >= n {break;}
z = x as i32;
let word = &self.s[sx][x];
if word == ";" {
if collecting {
collecting = false;
let index: usize = self.s.len();
self.s.push(Vec::<String>::new());
for item in self.func.drain(..) {
if self.s[index].len() > 0 &&
Self::appropriate(&self,&item,index)
{
let sx = *self.f.get(&self.s[index][0]).unwrap();
let n = self.s[sx].len();
for x in 1..n as usize {
let symbol = self.s[sx][x].clone();
self.s[index].push(symbol);
}
}
else {
self.s[index].push(item);
}
}
self.f.insert(self.s[index][0].clone(), index);
self.func.clear();
continue;
}
if 0 < xlist.len() {
(x, n) = xlist.pop().unwrap();
continue;
}
return Err(Error::InvalidWord);
}
if collecting {
self.func.push(String::from(word));
continue;
}
if Self::is_op(word) {
if self.v.len() < 2 {
return Err(Error::StackUnderflow);
}
let b = self.v.pop().unwrap();
let a = self.v.pop().unwrap();
let c = match word.as_str() {
"+" => a + b,
"-" => a - b,
"*" => a * b,
"/" => {if b == 0 {return Err(Error::DivisionByZero);} a / b},
_ => 0
};
self.v.push(c);
continue;
}
match word.parse::<Value>() {
Ok(value) => { self.v.push(value); continue;},
_ => {}
}
if word == ":" {
collecting = true;
self.func.clear();
continue;
}
if word == "drop" {
if self.v.len() < 1 {
return Err(Error::StackUnderflow);
}
self.v.pop();
continue;
}
if word == "dup" {
if self.v.len() < 1 {
return Err(Error::StackUnderflow);
}
let temp = self.v[self.v.len() - 1];
self.v.push(temp);
continue;
}
if !self.f.contains_key(word) {
return Err(Error::UnknownWord);
}
xlist.push((sx,n));
sx = *self.f.get(word).unwrap();
n = self.s[sx].len();
z = 0;
}
Ok(())
}
fn is_op(input: &str) -> bool {
match input {"+"|"-"|"*"|"/" => true, _ => false}
}
fn appropriate(&self, item:&str, index:usize) -> bool
{
false
}
fn prev_def_is_short(&self, index: usize) -> bool {
if index >= self.s.len() {
false
}
else {
if let Some(&sx) = self.f.get(&self.func[0]) {
self.s[sx].len() == 2
}
else {
false
}
}
}
}
The error message relates to the call to appropriate(). I haven't even written the body of that function yet; I'd like to get the parameters right first. The compiler's complaint is:
As a subroutine call
error[E0502]: cannot borrow `self` as immutable because it is also borrowed as mutable
--> src/lib.rs:85:47
|
81 | for item in self.func.drain(..) {
| -------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
...
85 | Self::appropriate(&self,&item,index)
| ^^^^^ immutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
as a method call
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src/lib.rs:85:29
|
81 | for item in self.func.drain(..) {
| -------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
...
85 | self.appropriate(&item,index)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
Is there any canonical way to deal with this situation?

The problem is that self.func.drain() will consume the elements contained in self.func, thus an exclusive (&mut) access is needed on self.func for the entire for loop.
If during the iteration you need to pass a reference to self globally, then its func member is potentially accessible while the loop holds an exclusive access to it: Rust forbids that.
Since you use drain() in order to consume all the elements inside self.func, I suggest you swap this vector with an empty one just before the loop, then iterate on this other vector that is not anymore part of self.
No copy of the content of the vector is involved here; swap() only deals with pointers.
Here is an over-simplified version of your code, adapted consequently.
struct Forth {
func: Vec<String>,
}
impl Forth {
fn eval(&mut self) {
/*
for item in self.func.drain(..) {
self.appropriate(&self);
}
*/
let mut func = Vec::new();
std::mem::swap(&mut self.func, &mut func);
for item in func.drain(..) {
let b = self.appropriate();
println!("{:?} {:?}", item, b);
}
}
fn appropriate(&self) -> bool {
false
}
}
fn main() {
let mut f = Forth {
func: vec!["aaa".into(), "bbb".into()],
};
f.eval();
}

Related

Why is Rust still borrowing after a match statement?

I have the following code:
use std::collections::HashMap;
type Elem = i64;
enum Op {
Num(Elem),
Add((String, String)),
}
type Statements = HashMap<String, Op>;
fn main() {
let mut statements = Statements::new();
statements.insert("lhs".to_string(), Op::Num(64));
statements.insert("op".to_string(), Op::Add(("lhs".to_string(), "rhs".to_string())));
statements.insert("rhs".to_string(), Op::Num(64));
let mut stack = Vec::new();
let mut op_name = "op";
loop {
let result: Elem;
match statements.get(op_name).unwrap() {
Op::Num(_) => {
panic!("{}: Did not expect Num", op_name);
},
Op::Add((lhs, rhs)) => {
if let Op::Num(lhs_value) = statements.get(lhs).unwrap() {
if let Op::Num(rhs_value) = statements.get(rhs).unwrap() {
result = lhs_value + rhs_value;
} else {
stack.push(op_name);
op_name = rhs;
continue;
}
} else {
stack.push(op_name);
op_name = lhs;
continue;
}
},
};
if let Some(new_op_name) = stack.pop() {
*(statements.get_mut(op_name).unwrap()) = Op::Num(result);
op_name = new_op_name;
} else {
println!("Result: {}", result);
return;
}
}
}
which gives me the following compiler error:
error[E0502]: cannot borrow `statements` as mutable because it is also borrowed as immutable
--> minimal.rs:43:15
|
22 | match statements.get(op_name).unwrap() {
| ----------------------- immutable borrow occurs here
...
43 | *(statements.get_mut(op_name).unwrap()) = Op::Num(result);
| ^^^^^^^^^^^-------^^^^^^^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0502`.
I was expecting the borrowing to end with the match statement, since I do not see how I could still access the result of the borrowing after this statement. Why is the value still being borrowed after the match statement?
Is there something I could do to make my code above work?
In my opinion you'll find it difficult to work with strings and strings references. I would rather switch to some type for your HashMap keys that would be small, and copyable, like an integer number. This way you'll not be required to deal with references and mutability - you can just copy your integers with little to no cost.
I resolved your compilation errors, but the overall code becomes more convoluted. Basically now each insert into the hash map will give you a unique integer ID of the operation. You can only query operations from the hash map using this provided ID. It also requires you to push statements in your hash map in the order of appearance. You can't insert add(lhs, rhs) unless you already know IDs of both lhs and rhs
use std::collections::HashMap;
type Elem = i64;
type StatementId = usize;
enum Op {
Num(Elem),
Add((StatementId, StatementId)),
}
#[derive(Default)]
struct StatementsRecord {
record: HashMap<StatementId, (String, Op)>,
next_statement_id: StatementId,
}
impl StatementsRecord {
fn insert(&mut self, name: String, operation: Op) -> StatementId {
self.record.insert(self.next_statement_id, (name, operation));
self.next_statement_id += 1;
self.next_statement_id - 1 // return id of newly stored operation
}
fn get(&self, id: &StatementId) -> Option<&(String, Op)> {
self.record.get(id)
}
fn get_mut(&mut self, id: &StatementId) -> Option<&mut (String, Op)> {
self.record.get_mut(id)
}
fn update(&mut self, id: &StatementId, value: Op) {
self.get_mut(id).unwrap().1 = value;
}
}
fn main() {
let mut statements = StatementsRecord::default();
let lhs_id = statements.insert("lhs".to_string(), Op::Num(64));
let rhs_id = statements.insert("rhs".to_string(), Op::Num(64));
// 64+64 = 128
let mut op_id = statements.insert("op".to_string(), Op::Add((lhs_id, rhs_id)));
// (64+64) + (64+64) = 256
let mut op_id = statements.insert("op".to_string(), Op::Add((op_id, op_id)));
let mut stack = Vec::new();
loop {
let result: Elem;
match statements.get(&op_id).unwrap() {
(op_name, Op::Num(_)) => {
panic!("{}: Did not expect Num", op_name);
},
(op_name, Op::Add((lhs, rhs))) => {
if let (_, Op::Num(lhs_value)) = statements.get(lhs).unwrap() {
if let (_, Op::Num(rhs_value)) = statements.get(rhs).unwrap() {
result = lhs_value + rhs_value;
} else {
stack.push(op_id);
op_id = *rhs;
continue;
}
} else {
stack.push(op_id);
op_id = *lhs;
continue;
}
},
};
if let Some(new_op_id) = stack.pop() {
statements.update(&op_id, Op::Num(result));
op_id = new_op_id;
} else {
println!("Result: {}", result);
return;
}
}
}
Prints
Result: 256

Refactoring methods of a Struct: Cannot borrow `*self` as immutable because it is also borrowed as mutable

I would like to create a structure where one field is evolving in function of the others. I can do it, but I think it can be cleverly refactored.
Here is the minimal code for such a goal:
struct Example {
data: Vec<bool>,
elements: Vec<usize>,
data2: bool
}
impl Example {
fn decide(&self, index: usize)-> usize{
let mut counter = 0;
for (i,&b) in self.data.iter().enumerate() {
if b && i < index && self.data2 {
counter += 1;
}
}
counter
}
fn evolve(&mut self){
for element in self.elements.iter_mut(){
if self.decide(*element) == 4 {
*element += 1
}
}
}
}
The compiler says that there is an error:
`
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src/lib.rs:20:16
|
19 | for element in self.elements.iter_mut() {
| ------------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
20 | if self.decide(*element) == 4 {
| ^^^^^^^^^^^^^^^^^^^^^ immutable borrow occurs here
In this precise example, it is easy to replace line 13 by if self.decide(*element) == 4 { by the whole definition of the decide function and it works:
struct Example {
data: Vec<bool>,
elements: Vec<usize>,
data2: bool,
}
impl Example {
fn evolve(&mut self) {
for element in self.elements.iter_mut() {
let mut counter = 0;
for (i, &b) in self.data.iter().enumerate() {
if b && i < *element && self.data2 {
counter += 1;
}
}
if counter == 4 {
*element += 1
}
}
}
}
But in my case, the decide function is big and I want to reduce the size of evolve. Is it possible to do so?
The easiest fix is to pass decide() the data it needs instead of it taking &self:
fn decide(data: &[bool], data2: bool, index: usize) -> usize {
let mut counter = 0;
for (i, &b) in data.iter().enumerate() {
if b && i < index && data2 {
counter += 1;
}
}
counter
}
fn evolve(&mut self) {
for element in self.elements.iter_mut() {
if Self::decide(&self.data, self.data2, *element) == 4 {
*element += 1
}
}
}
Playground

Linked list. Can't change borrowed value

I am on my way of learning Rust. In practical purpose I decided to make my own linked list collection. But I faced with some problems soon. I tried but can't find any way to fix this problem. Can I do this using this type of structure for linked list? The main problem I faced is implementation of deleting function.This function should delete element from the list with replacing address of the current node with address of the next node. But I can't change the value because it was borrowed already.
#[derive(Debug, PartialEq)]
enum AlmostList {
Cons(i32, Box<AlmostList>),
Nil,
}
The base of linked list is enumeration.
#[derive(Debug, PartialEq)]
struct List {
length: u32,
data: AlmostList,
}
But I want the instance of list knows its own length. Because of it I decided to use structure to store the length of the list in it.
use crate::AlmostList::{Cons, Nil};
//Implementetion of functions
impl List {
fn new() -> List {
List{ length: 0_u32, data: AlmostList::Nil }
}
fn append(&mut self, elem: i32) {
let mut alist = &mut self.data;
loop {
match alist {
Cons(_, ref mut ptr) => alist = ptr,
Nil => {
let node = Cons(elem, Box::new(Nil));
self.length += 1;
*alist = node;
break;
},
}
}
}
fn show(&self) {
let mut alist = &self.data;
if let Nil = alist {
panic!("List is empty");
}
loop {
match alist {
Cons(value, ptr) => {
print!("{} ", value);
alist = &*ptr;
},
Nil => break,
}
}
}
}
Everything was fine until I started to write function of deleting elements.This function should delete element from the list with replacing address of the current node with address of the next node.
fn delete(&mut self, number: i32) -> Option<i32> {
let mut alist = &mut self.data;
let result = loop {
match alist {
Cons(value, ptr) => {
if *value != number {
alist = ptr;
}
self.length -= 1;
*alist = *ptr.clone();
break Some(number);
},
Nil => break None,
}
};
result
}
}
Got this error:
error[E0506]: cannot assign to `*alist` because it is borrowed
--> main.rs:79:25
|
73 | Cons(value, ptr) => {
| --- borrow of `*alist` occurs here
...
79 | *alist = *ptr.clone();
| ^^^^^^
| |
| assignment to borrowed `*alist` occurs here
| borrow later used here
error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as mutable
--> main.rs:79:35
|
75 | alist = ptr;
| --- mutable borrow occurs here
...
79 | *alist = *ptr.clone();
| ------ ^^^ immutable borrow occurs here
| |
| mutable borrow later used here
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0502, E0506.
For more information about an error, try `rustc --explain E0502`.
Can I solve this problem somehow?
Yes, you can solve this problem. I fixed it in that way:
pub fn delete(&mut self, number: i32) -> Option<i32> {
let mut alist = &mut self.data;
let result = loop {
match alist {
AlmostList::Cons(value, ref mut ptr) => {
if *value != number {
alist = ptr;
} else {
break Some(ptr);
}
}
AlmostList::Nil => break None,
}
};
if let Some(ptr) = result {
*ptr = Box::new(AlmostList::Nil);
Some(number)
} else {
None
}
}
At least the code above was compiled successfully. Full rust playground example: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5bd28014bdec30e5c2e851827f15dad5
Additional hints:
write better namings. Examples: AlmostLeast -> ListNode (or just Node), Nil -> None, Cons -> Some. I have feeling that you have experience with Lisp in the past :)
format your code with cargo fmt and check with cargo clippy
any data structure implementations should not panic. Use Result type
Update:
Code above is wrong. I've implemented it using recursion: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ea6dbd3a627a59014df823be29e296b2

How can you modify edge weights for a filtered Petgraph graph?

I am using an edge filter for my graph and want to update an edge weight:
use petgraph::prelude::*;
use petgraph::graph;
use petgraph::visit::{Dfs, EdgeFiltered, IntoEdges};
fn filter_edges(edge: graph::EdgeReference<u32>) -> bool {
match edge.weight() {
0 => true,
_ => false,
}
}
fn main() {
let mut graph: graph::Graph<u32, u32> = graph::Graph::new();
let a = graph.add_node(1);
let b = graph.add_node(2);
let e = graph.add_edge(a, b, 0);
let mut filtered_graph = EdgeFiltered::from_fn(&graph, filter_edges);
let mut dfs = Dfs::new(&filtered_graph, a);
while let Some(node_index) = dfs.next(&filtered_graph) {
for edge in filtered_graph.edges(node_index) {
filtered_graph.update_edge(edge.source(), edge.target(), 1);
//graph.update_edge(edge.source(), edge.target(), 1);
}
}
}
But this errors because EdgeFiltered doesn't have an update_edge function:
error[E0599]: no method named `update_edge` found for struct `EdgeFiltered<&Graph<u32, u32>, for<'r> fn(petgraph::graph::EdgeReference<'r, u32>) -> bool {filter_edges}>` in the current scope
--> src/main.rs:22:28
|
22 | filtered_graph.update_edge(edge.source(), edge.target(), 1);
| ^^^^^^^^^^^ method not found in `EdgeFiltered<&Graph<u32, u32>, for<'r> fn(petgraph::graph::EdgeReference<'r, u32>) -> bool {filter_edges}>`
If I switch to refer to the original graph instead, it has a borrow checker error (unlike Dfs, unfortunately EdgeFiltered isn't designed to let you access the original graph):
error[E0502]: cannot borrow `graph` as mutable because it is also borrowed as immutable
--> src/main.rs:21:13
|
17 | let mut filtered_graph = EdgeFiltered::from_fn(&graph, filter_edges);
| ------ immutable borrow occurs here
18 | let mut dfs = Dfs::new(&filtered_graph, a);
19 | while let Some(node_index) = dfs.next(&filtered_graph) {
| --------------- immutable borrow later used here
20 | for edge in filtered_graph.edges(node_index) {
21 | graph.update_edge(edge.source(), edge.target(), 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
Playground link for the above
Edgefiltered is pretty minimal, and doesn't really seem to have anything intended for mutable graph manipulation. Is there any way to do this with what Petgraph comes with, or will I have to write my own version of update_edge showhow?
FilteredGraph borrows the Graph, therefore you cannot get a mutable reference to the Graph as long as FilteredGraph exists.
You can re-create a FilteredGraph on each dfs.next() call to work around this, e.g. this works:
use petgraph::graph;
use petgraph::visit::{Dfs, EdgeFiltered};
fn filter_edges(edge: graph::EdgeReference<u32>) -> bool {
match edge.weight() {
0 => true,
_ => false,
}
}
fn main() {
let mut graph: graph::Graph<u32, u32> = graph::Graph::new();
let a = graph.add_node(1);
let b = graph.add_node(2);
let e = graph.add_edge(a, b, 0);
let filtered_graph = EdgeFiltered::from_fn(&graph, filter_edges);
let mut dfs = Dfs::new(&filtered_graph, a);
while let Some(node_index) = dfs.next(&EdgeFiltered::from_fn(&graph, filter_edges)) {
let mut neighbors = graph.neighbors(node_index).detach();
while let Some((edge_idx, _)) = neighbors.next(&graph) {
graph[edge_idx] = 1;
}
}
}
Note: This will take the neighbors of the given node based on the edges present in graph, not by those present in filtered_graph.
You can solve that by ditching EdgeFiltered and manually handling it in the traversal, e.g. like this:
fn main() {
let mut graph: graph::Graph<u32, u32> = graph::Graph::new();
let a = graph.add_node(1);
let b = graph.add_node(2);
let e = graph.add_edge(a, b, 0);
let mut dfs = Dfs::new(&graph, a);
while let Some(node_index) = dfs.next(&graph) {
let mut neighbors = graph.neighbors(node_index).detach();
while let Some((edge_idx, _)) = neighbors.next(&graph) {
let edge_weight = &mut graph[edge_idx];
if *edge_weight == 0 {
*edge_weight = 1;
}
}
}
}

Rust tells ''value moved here, in previous iteration of loop"

I'm implementing a parser combinator library:
#[derive(Debug)]
enum Parser {
Char(char),
Positive(Box<Parser>),
}
impl Parser {
fn run(self, s: &str) -> (bool, &str) {
match self {
Parser::Char(ch) => {
if s[0..1].chars().next().unwrap() == ch {
(true, &s[1..])
} else {
(false, s)
}
}
Parser::Positive(parser) => {
//println!("{:?}", parser);
let mut s = s;
let mut res = (false, s);
let parser = *parser;
loop {
let ret = parser.run(s);
if !ret.0 {
break;
}
res = ret;
s = res.1
}
res
}
_ => (false, s),
}
}
}
pub fn run() {
let x = Parser::Positive(Box::new(Parser::Char('a')));
let ret = x.run("aaa");
println!("{} {}", ret.0, ret.1);
}
I'm getting the error
error[E0382]: use of moved value: `parser`
--> src/lib.rs:25:31
|
22 | let parser = *parser;
| ------ move occurs because `parser` has type `Parser`, which does not implement the `Copy` trait
...
25 | let ret = parser.run(s);
| ^^^^^^ value moved here, in previous iteration of loop
I have no idea why this happens. I've tried to add the Copy trait to the Parser enum, but this causes other errors. Why can't I call parser.run() in a loop, or even twice? A single call compiles and runs perfectly.
Would it be better to use a struct instead of an enum?
OK, changed the function's signature to
fn run<'a>(&self, s: &'a str) -> (bool, &'a str)
now and needed some other lines to be fixed.
Works now, but I don't know why.

Resources