Borrow checker "cannot move out of borrowed content" [duplicate] - rust

This question already has answers here:
Cannot move out of value which is behind a shared reference when unwrapping
(2 answers)
error[E0507]: Cannot move out of borrowed content
(1 answer)
cannot move out of borrowed content when unwrapping a member variable in a &mut self method
(2 answers)
Closed 4 years ago.
Why can't I do this?
pub fn start_workers(&mut self) {
// start all the worker threads
self.dispatch_thread = Some(spawn(||{
for _i in 1..10 {
println!("Price = {}", 10);
thread::sleep(time::Duration::from_secs(1));
}
}));
self.dispatch_thread.unwrap().join();
}
I'm getting the following error,
error[E0507]: cannot move out of borrowed content
--> src/orderbook.rs:195:9
|
195 | self.dispatch_thread.unwrap().join();
| ^^^^ cannot move out of borrowed content

This is indeed a non-obvious error message. Have a look at the method signatures for unwrap:
pub fn unwrap(self) -> T
and take:
pub fn take(&mut self) -> Option<T>
unwrap consumes the Option (note the receiver is self), which would leave self.dispatch_thread in an unknown state. If you use take it is returned to the None state as you probably intended.
You probably want take in this context; as shown here:
use std::thread;
use std::time;
struct Foo {
foo: Option<thread::JoinHandle<()>>,
}
impl Foo {
fn nope(&mut self) {
self.foo = Some(thread::spawn(|| {
for _i in 1..10 {
println!("Price = {}", 10);
thread::sleep(time::Duration::from_millis(10));
}
}));
self.foo.take().unwrap().join();
}
}
fn main() {
let foo = Some(thread::spawn(|| {
for _i in 1..10 {
println!("Price = {}", 10);
thread::sleep(time::Duration::from_millis(10));
}
}));
foo.unwrap().join();
let mut foo = Foo { foo: None };
foo.foo = Some(thread::spawn(|| {
for _i in 1..10 {
println!("Price = {}", 10);
thread::sleep(time::Duration::from_millis(10));
}
}));
foo.foo.unwrap().join();
let mut foo = Foo { foo: None };
foo.nope();
}
Note that assert!(foo.foo.is_none()); would be similarly illegal; but is valid in this case because we don't violate that constraint. In the method with &self as a receiver, this isn't true, which is why it is illegal in that case.

Related

Is there a way to tell rustc when is is being too conservative about certain borrows?

I'm playing around with building a very simple stack based evaluator in Rust and I've come up against an odd situation where I think the borrow checker is being too conservative:
use std::collections::HashMap;
pub type Value = i32;
pub type Result = std::result::Result<(), Error>;
type Op = Box<dyn Fn(&mut Evaluator) -> Result>;
type OpTable = HashMap<String, Op>;
pub struct Evaluator {
stack: Vec<Value>,
ops: OpTable,
}
#[derive(Debug, PartialEq)]
pub enum Error {
DivisionByZero,
StackUnderflow,
UnknownWord,
InvalidWord,
}
impl Evaluator {
fn add(&mut self) -> Result {
if let (Some(x), Some(y)) = (self.stack.pop(), self.stack.pop()) {
self.stack.push(y + x);
Ok(())
} else {
Err(Error::StackUnderflow)
}
}
fn sub(&mut self) -> Result {
if let (Some(x), Some(y)) = (self.stack.pop(), self.stack.pop()) {
self.stack.push(y - x);
Ok(())
} else {
Err(Error::StackUnderflow)
}
}
pub fn new() -> Evaluator {
let stack: Vec<Value> = vec![];
let mut ops: OpTable = HashMap::new();
ops.insert("+".to_string(), Box::new(Evaluator::add));
ops.insert("-".to_string(), Box::new(Evaluator::sub));
Evaluator { stack, ops }
}
pub fn eval(&mut self, input: &str) -> Result {
let symbols = input.split_ascii_whitespace().collect::<Vec<_>>();
// user definition
if let (Some(&":"), Some(&";")) = (symbols.first(), symbols.last()) {
if symbols.len() > 3 {
let statement = symbols[2..symbols.len() - 1].join(" ");
self.ops.insert(
symbols[1].to_string().to_ascii_lowercase(),
Box::new(move |caller: &mut Evaluator| caller.exec(&statement)),
);
return Ok(());
} else {
return Err(Error::InvalidWord);
}
}
self.exec(input)
}
fn exec(&mut self, input: &str) -> Result {
let symbols = input.split_ascii_whitespace().collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if let Some(f) = self.ops.get(&s) { // <--------------errors here
f(self)?; // <----------------------------|
} else {
return Err(Error::InvalidWord);
}
}
}
Ok(())
}
}
fn main() {
let mut e = Evaluator::new();
e.eval("1 2 +");
println!("{:?}", e.stack);
e.eval(": plus-1 1 + ;");
e.eval("4 plus-1");
println!("{:?}", e.stack);
}
I'm getting:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:77:21
|
76 | if let Some(f) = self.ops.get(&s) {
| -------- immutable borrow occurs here
77 | f(self)?;
| -^^^^^^
| |
| mutable borrow occurs here
| immutable borrow later used by call
For more information about this error, try `rustc --explain E0502`.
error: could not compile `evaluator` due to previous error
I believe this is because taking part of the hashmap (f) borrows all of self immutably, then I'm passing self mutably to f(). However, there is no real conflict here (I think).
I'm able to get around this by actually removing and reinserting the value:
fn exec(&mut self, input: &str) -> Result {
let symbols = input.split_ascii_whitespace().collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if self.ops.contains_key(&s) {
let f = self.ops.remove(&s).unwrap();
if let Err(e) = f(self) {
self.ops.insert(s, f);
return Err(e);
}
self.ops.insert(s, f);
} else {
return Err(Error::InvalidWord);
}
}
}
Ok(())
}
But this feels hacky and is a lot more verbose and inefficient. Am I missing something? Is there a way to tell the compiler the first version is ok?
The compiler is entirely correct, and so is your explanation: The call to get() needs a borrow on self.ops to return an &Op of the same lifetime. You then try to call that FnMut with a mutable borrow of self; this mutable borrow of self aliases with the immutable borrow on self.ops, and in theory it would be possible for an implementation of this FnMut to modify that borrowed Op through self, which is not allowed. The compiler prevented a situation where mutation occurs through an aliased pointer.
This situation often occurs when passing &mut self around, as immutable borrows on members of self which result in more borrows (&self.ops.get() has the same lifetime as &self) "lock" all of self.
While your second example is cumbersome, it is at least correct as proven by the compiler: By removing Op from the hashtable, the FnMut can't reach itself through self anymore, and mutation while aliasing is prevented.
A better approach is usually to avoid taking &mut self as an argument (&mut self as in &mut Executor).

How do I consume the inner value of a Rc<RefCell<Option<_>>>? [duplicate]

This question already has answers here:
How do I move out of a struct field that is an Option?
(1 answer)
How can I swap in a new value for a field in a mutable reference to a structure?
(2 answers)
Closed 3 years ago.
I have a function of a third party library that needs ownership of a variable. Unfortunately this variable is inside a Rc<RefCell<Option<Foo>>>.
My code looks simplified like this:
use std::cell::RefCell;
use std::rc::Rc;
pub struct Foo {
val: i32,
}
fn main() {
let foo: Rc<RefCell<Option<Foo>>> = Rc::new(RefCell::new(Some(Foo { val: 1 })));
if let Some(f) = foo.into_inner() {
consume_foo(f);
}
}
fn consume_foo(f: Foo) {
println!("Foo {} consumed", f.val)
}
error[E0507]: cannot move out of an `Rc`
--> src/main.rs:11:22
|
11 | if let Some(f) = foo.into_inner() {
| ^^^ move occurs because value has type `std::cell::RefCell<std::option::Option<Foo>>`, which does not implement the `Copy` trait
I tried to use std::mem::replace(...) from How can I swap in a new value for a field in a mutable reference to a structure?:
fn main() {
let mut foo: Rc<RefCell<Option<Foo>>> = Rc::new(RefCell::new(Some(Foo { val: 1 })));
let mut foo_replaced = std::mem::replace(&mut foo.into_inner(), None);
if let Some(f) = foo_replaced.take() {
consume_foo(f);
}
}
error[E0507]: cannot move out of an `Rc`
--> src/main.rs:11:51
|
11 | let mut foo_replaced = std::mem::replace(&mut foo.into_inner(), None);
| ^^^ move occurs because value has type `std::cell::RefCell<std::option::Option<Foo>>`, which does not implement the `Copy` trait
I can't figure out how to do this properly.

Closure referring to a method of self: borrow error [duplicate]

This question already has answers here:
Mutably borrow one struct field while borrowing another in a closure
(2 answers)
Closed 5 years ago.
Here is the interesting part:
struct S1 {}
impl S1 {
pub fn new() -> Self {
S1 {}
}
pub fn foo<F>(&self, mut delegate: F) -> ()
where
F: FnMut() -> (),
{
delegate()
}
}
struct S2 {
s1: S1,
done: bool,
}
impl S2 {
pub fn new() -> Self {
S2 {
s1: S1::new(),
done: false,
}
}
fn actually_do_something(&mut self) -> () {
self.done = true
}
pub fn do_something(&mut self) -> () {
self.s1.foo(|| {
self.actually_do_something();
})
}
}
The actual error generated is:
error[E0500]: closure requires unique access to `self` but `self.s1` is already borrowed
--> src/main.rs:34:21
|
34 | self.s1.foo(|| {
| ------- ^^ closure construction occurs here
| |
| borrow occurs here
35 | self.actually_do_something();
| ---- borrow occurs due to use of `self` in closure
36 | })
| - borrow ends here
I understand why I get this error (having multiple overlapping mutable borrows of self), yet I can't find a proper way to solve it. Taking multiple deep references to my object here doesn't seem to be possible as I'm calling a self method directly.
A way of doing this is to destructure your struct. Here is a sample with your code:
pub fn do_something(&mut self) -> () {
let &mut S2 { ref mut s1, ref mut done } = self;
s1.foo(|| {
*done = true;
})
}
Playground

How to change the variable from inside Fn closure in Rust?

I have the following code (playground):
struct A {
pub vec: Vec<u64>,
}
impl A {
fn perform_for_all<F: Fn(&mut u64)>(&mut self, f: F) {
for mut i in &mut self.vec {
f(i);
}
}
}
fn main() {
let mut a = A {
vec: vec![1, 3, 44, 2, 4, 5, 6],
};
let mut done = false;
a.perform_for_all(|v| {
println!("value: {:?}", v);
done = true;
});
if !done {
a.perform_for_all(|v| {
println!("value {:?}", v);
});
}
}
The following errors occur:
error[E0594]: cannot assign to `done`, as it is a captured variable in a `Fn` closure
--> src/main.rs:21:9
|
21 | done = true;
| ^^^^^^^^^^^ cannot assign
|
help: consider changing this to accept closures that implement `FnMut`
--> src/main.rs:19:23
|
19 | a.perform_for_all(|v| {
| _______________________^
20 | | println!("value: {:?}", v);
21 | | done = true;
22 | | });
| |_____^
I have a list of loaded objects and a list of objects in a database. I need a function that takes a closure and executes it on the loaded objects and if we don't have the objects in the list, execute it on a list of objects from the database.
That function looks like:
pub fn perform_for_match_with_mark<F>(&mut self, mark: MatchMark, f: F)
where
F: Fn(&mut GameMatch),
{
self.perform_for_all_matches(
|m| {
// runtime list
if let Game::Match(ref mut gm) = *m {
if gm.match_stamp().mark == mark {
f(gm);
}
}
},
None,
);
// if we have called `f` above - don't execute lines below.
let tx = self.match_tx.clone();
GamesDatabase::perform_for_match_with_mark(mark, |ms| {
// database
self.perform_for_all_matches(
|m| {
if let Game::Match(ref gm) = *m {
if gm.match_stamp().id == ms.id {
f(&mut GameMatch::new_with_match_stamp(
tx.clone(),
ms.clone(),
gm.needs_server_set,
gm.server_id,
))
}
}
},
None,
);
});
}
We have to operate on objects from the database only if we were unable to find them in runtime list. That is why I decided to make a variable which says "we already found these objects in the list, leave the database alone".
Change your perform_for_all function to use FnMut instead of Fn:
fn perform_for_all<F>(&mut self, mut f: F)
where
F: FnMut(&mut u64),
{
for mut i in &mut self.vec {
f(&mut i);
}
}
As Peter said, there is some compiler magic going on.
The signature for Fn::call is:
extern "rust-call" fn call(&self, args: Args) -> Self::Output
This takes an immutable reference to self, which is why you can't modify any of the captured variables.
The signature for FnMut::call_mut lets you mutate variables because it takes &mut self:
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output
By changing your closure from Fn to FnMut, you allow it to modify its captured variables, given that the references you pass to it are mutable.
Just to expand a little on SplittyDev's answer.
When you use a closure, the compiler does some magic to let the closure access variables in its environment. Effectively it will create a new struct, whose members are the variables that you tried to access.
It's not exactly this (which won't actually compile), but it's a reasonable approximation conceptually:
struct Closure_1 {
done: bool
}
impl FnMut<&mut u64> for Closure_1 {
fn call_mut(&mut self, v: &mut u64) {
println!("value: {:?}", v);
self.done = true;
}
}
And when you call it, those variables will be borrowed or copied (or moved if you use move keyword).
let mut c1 = Closure_1 { done : done };
a.perform_for_all(|v| c1.call(&v));
done = c1.done;
When the closure modifies its environment, it cannot be a Fn because it must also mutate the variables on itself:
impl Fn<&mut u64> for Closure_1 {
fn call(&self, v: &mut u64) {
println!("value: {:?}", v);
self.done = true; // Can't do this because self is not a mutable ref
}
}
See The Rust Programming Language section on closures and their environment for more information.

Rewriting adding to a singly linked stack from a recursive implementation to iterative [duplicate]

This question already has answers here:
Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time
(4 answers)
Closed 4 years ago.
To learn Rust, I am implementing an AVL tree/dictionary. To insert a new element, I descend into the tree until I find a node where it could be inserted. Unfortunately it complains about several issues with borrowing pointers, and I'm having trouble deciphering them.
I've highlighted where and which errors occur.
enum AVLTree<T, U> {
Tree(T, U, Box<AVLTree<T, U>>, Box<AVLTree<T, U>>),
Empty,
}
impl<T, U> AVLTree<T, U>
where T: PartialOrd + PartialEq + Copy,
U: Copy
{
fn insert_element(&mut self, key: T, val: U) {
let new_node = AVLTree::Tree(key, val, Box::new(AVLTree::Empty), Box::new(AVLTree::Empty));
if let AVLTree::Empty = *self {
*self = new_node;
return;
}
let mut at = self;
loop {
match at {
&mut AVLTree::Tree(key2, _, ref mut left, ref mut right) => {
// ^~~~~~~~~~~~
// error: cannot borrow `at.2` as mutable more than once at a time
// ^~~~~~~~~~~~~
// error: cannot borrow `at.3` as mutable more than once at a time
if key < key2 {
if let AVLTree::Empty = **left {
*left = Box::new(new_node);
break;
}
at = &mut **left;
// error: cannot assign to `at` because it is borrowed
} else {
if let AVLTree::Empty = **right {
*right = Box::new(new_node);
break;
}
at = &mut **right;
// error: cannot assign to `at` because it is borrowed
}
}
&mut AVLTree::Empty => unreachable!(),
}
}
// Do something
}
}
Why is deconstructing at borrowing it? Why is the compiler complaining about multiple mutable borrows when this should never happen? How could this code be written instead to avoid such errors?
This seems to be a weakness of the borrow checker, and is perhaps a bug. The problem is that you are borrowing at in the match and then modifying it. Unfortunately, the compiler doesn't see that the at inside the loop and outside the loop are conceptually different. We can make them explicitly different, however:
enum AVLTree {
Tree(Box<AVLTree>),
Empty,
}
impl AVLTree {
fn insert_element(&mut self) {
let mut at = self;
loop {
let tmp_at = at; // Main change
match tmp_at {
&mut AVLTree::Tree(ref mut left) => {
at = &mut **left;
}
&mut AVLTree::Empty => unreachable!()
}
}
}
}
fn main() {}
Here, we transfer the mutable borrow from at to tmp_at, then transfer it to left, then transfer it back to at.
A prettier option may be to use a new scope:
fn insert_element(&mut self) {
let mut at = self;
loop {
match {at} { // Main change
&mut AVLTree::Tree(ref mut left) => {
at = &mut **left;
}
&mut AVLTree::Empty => unreachable!(),
}
}
}

Resources