Using references in arguments in a method call on a mutable reference - rust

This Rust code works:
let a = self.stack.pop_or_err()?;
let b = self.stack.pop_or_err()?;
self.stack.push(a * b);
(The ?s are unimportant, just an application detail.)
If i turn it into:
self.stack.push(self.stack.pop_or_err()? * self.stack.pop_or_err()?);
the I see:
error[E0499]: cannot borrow `self.stack` as mutable more than once at a time
--> src/question2.rs:121:33
|
121 | self.stack.push(self.stack.pop_or_err()? + self.stack.pop_or_err()?);
| ----------------^^^^^^^^^^^^^^^^^^^^^^^-----------------------------
| | | |
| | | second mutable borrow occurs here
| | first borrow later used by call
| first mutable borrow occurs here
error[E0499]: cannot borrow `self.stack` as mutable more than once at a time
--> src/question2.rs:121:60
|
121 | self.stack.push(self.stack.pop_or_err()? + self.stack.pop_or_err()?);
| -------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^--
| | | |
| | | second mutable borrow occurs here
| | first borrow later used by call
| first mutable borrow occurs here
Is there a one-line form of calling a method on a mut reference which uses the reference in arguments in the method call?

As #Netwave mentioned, I don't think there's a clean way to do this, but I have the following gibberish which does the trick:
(|x: i32, v: &mut Vec<i32>| v.push(x))(v.pop()? * v.pop()?, &mut v);
Each call to pop takes a mutable reference, but then drops it, so we can do the product in one expression. However, passing the mutable reference to v will hold on to it, so we must pass that to the closure second. This is also why we have to pass &mut v to the closure explicitly rather than capturing it. I believe the reason for using the push method directly not working is that it takes &mut self as the first argument.
I by no means recommend this! But it is possible.

Related

Access variable after it was borrowed

I am assigning data to properties of a struct, but the following error appears:
error[E0382]: borrow of partially moved value: `super_hero`
--> src/main.rs:16:22
|
13 | for mut chunk in super_hero.description_chunks.unwrap() {
| -------- `super_hero.description_chunks` partially moved due to this method call
...
16 | println!("{:?}", &super_hero);
| ^^^^^^^ value borrowed here after partial move
|
note: this function takes ownership of the receiver `self`, which moves `super_hero.description_chunks`
--> /Users/someuser/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:752:25
|
752 | pub const fn unwrap(self) -> T {
| ^^^^
= note: partial move occurs because `super_hero.description_chunks` has type `std::option::Option<Vec<Chunk>>`, which does not implement the `Copy` trait
help: consider calling `.as_ref()` to borrow the type's contents
|
13 | for mut chunk in super_hero.description_chunks.as_ref().unwrap() {
| +++++++++
The following is the code where I am assigning data to properties of a struct:
let super_hero_description = "several years ago.";
let mut super_hero = SuperHero::new(super_hero_description);
super_hero.description_chunks = Option::from(super_hero.get_decription_chunks(DescriptionTypes::NotVillan));
for mut chunk in super_hero.description_chunks.unwrap() {
chunk.data = Option::from(chunk.get_data(DescriptionTypes::NotVillan).await);
}
println!("{:?}", &super_hero);
The error does not happen until I try to print the super_hero at the end.
Oh, and if I follow the recommendation rust gives me
for mut chunk in super_hero.description_chunks.as_ref().unwrap() {
| +++++++++
I end up with another error:
error[E0594]: cannot assign to `chunk.data`, which is behind a `&` reference
--> src/main.rs:14:9
|
13 | for mut subdivision in super_hero.description_chunks.as_ref().unwrap() {
| ------------------------------------- this iterator yields `&` references
14 | chunk.data = Option::from(chunk.get_data()(DescriptionTypes::NotVillan).await);
| ^^^^^^^^^^^^ `chunk` is a `&` reference, so the data it refers to cannot be written
rustc is correct, it just needs a little adjustment: instead of as_ref() use as_mut(), that converts &mut Option<T> to Option<&mut T> instead of &Option<T> to Option<&T>.
The problem is that unwrap() requires an owned Option: see Reference to unwrapped property fails: use of partially moved value: `self`.

Rust moving value into both sides of map_or_else?

Rust has a method on an enum called .map_or_else() it takes two closures one of which triggers on None, the other triggers on Some(inner) passing inner.
This is great, but what I want to do is move a value into both branches of it. This generates an error,
error[E0382]: borrow of moved value: `result`
--> src/sequence/renderer.rs:124:5
|
104 | let result = match self.display {
| ------ move occurs because `result` has type `String`, which does not implement the `Copy` trait
...
123 | || Ok(result),
| -- ------ variable moved due to use in closure
| |
| value moved into closure here
124 | |v| Ok(format!("{:0>width$}", result.clone(), width=v as usize ))
| ^^^ ------ borrow occurs due to use in closure
| |
| value borrowed here after move)
This error can be be solved by replacing the first closure to .map_or_else with,
Ok(result.clone())
But is this a good idea? Then I have to clone() a string for no benefit? What is the idiomatic way to use .map_or_else() when both sides need access to the same variable?
Unfortunately there is no way for this to work, since Rust has no way of annotating the two closures as "only one will get invoked".
So your best bet is to not use the higher-level function and instead write a simple match expression.

Spawning threads and keeping data from them

This is a super contrived example that shows what I want to do; I have a HashMap that I want to push data in to, but I want to do it in a set of threads - the real example is that I'm connecting to a remote service inside the thread::spawn and so I want to have all of it happen in the background as much as possible so it doesn't block the primary thread.
I'm not sure how to refactor my code to allow what I'm wanting to do - any suggestions would be helpful!
let mut item_array : HashMap<i32, i32> = HashMap::new();
let mut array: [i32; 3] = [0, 1, 2];
for item in &array {
thread::spawn(|| {
item_array.insert(*item, *item);
});
}
println!("{:?}", item_array);
The errors I receive are below
error[E0597]: `array` does not live long enough
--> src/main.rs:87:17
|
87 | for item in &array {
| ^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `array` is borrowed for `'static`
...
153 | }
| - `array` dropped here while still borrowed
error[E0499]: cannot borrow `item_array` as mutable more than once at a time
--> src/main.rs:88:23
|
88 | thread::spawn(|| {
| - ^^ mutable borrow starts here in previous iteration of loop
| _________|
| |
89 | | item_array.insert(*item, *item);
| | ---------- borrows occur due to use of `item_array` in closure
90 | | });
| |__________- argument requires that `item_array` is borrowed for `'static`
error[E0373]: closure may outlive the current function, but it borrows `item`, which is owned by the current function
--> src/main.rs:88:23
|
88 | thread::spawn(|| {
| ^^ may outlive borrowed value `item`
89 | item_array.insert(*item, *item);
| ---- `item` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src/main.rs:88:9
|
88 | / thread::spawn(|| {
89 | | item_array.insert(*item, *item);
90 | | });
| |__________^
help: to force the closure to take ownership of `item` (and any other referenced variables), use the `move` keyword
|
88 | thread::spawn(move || {
| ^^^^^^^
error[E0373]: closure may outlive the current function, but it borrows `item_array`, which is owned by the current function
--> src/main.rs:88:23
|
88 | thread::spawn(|| {
| ^^ may outlive borrowed value `item_array`
89 | item_array.insert(*item, *item);
| ---------- `item_array` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src/main.rs:88:9
|
88 | / thread::spawn(|| {
89 | | item_array.insert(*item, *item);
90 | | });
| |__________^
help: to force the closure to take ownership of `item_array` (and any other referenced variables), use the `move` keyword
|
88 | thread::spawn(move || {
| ^^^^^^^
error[E0502]: cannot borrow `item_array` as immutable because it is also borrowed as mutable
--> src/main.rs:92:22
|
88 | thread::spawn(|| {
| - -- mutable borrow occurs here
| _________|
| |
89 | | item_array.insert(*item, *item);
| | ---------- first borrow occurs due to use of `item_array` in closure
90 | | });
| |__________- argument requires that `item_array` is borrowed for `'static`
91 | }
92 | println!("{:?}", item_array);
| ^^^^^^^^^^ immutable borrow occurs here
There are two problems here (which are typical problems with multithreaded Rust):
Your thread cannot borrow any data that may outlive it (which, when using std::thread::spawn, is any data1).
Multiple thread cannot borrow the same mutable data.
The first problem is typically solved by:
Copying data instead of referencing it. This is particularly useful for primitive types, such as integers.
Using scoped threads.
Using Arc for thread-safe shared pointer, to ensure that data outlives all threads using it.
Not all are possible in all cases, but I'd recommend the above solutions in that order.
The second problem is typically solved with locks such as Mutex or RwLock, which allows only a single thread to get a mutable reference at a time.
Combining these, I'd solve your example like this:
// mutable data is wrapped in a Mutex
let item_array: Mutex<HashMap<i32, i32>> = Mutex::new(HashMap::new());
// immutable data does not have to be wrapped with scoped threads
let array: [i32; 3] = [0, 1, 2];
// using crossbeam::scope from the crossbeam library, which lets
// us reference variables outside the scope (item_array and array)
crossbeam::scope(|s| {
for item in &array {
// copy item (since it is an integer)
let item = *item;
// explicitly reference item_array, since we'll later need to move this
let item_array_ref = &item_array;
// move item and item_array_ref into the closure (instead of referencing,
// which is by default)
s.spawn(move |_| {
// need to call .lock() to aquire a mutable reference to the HashMap
// will wait until the mutable reference is not used by any other threads
let mut item_array_lock = item_array_ref.lock().unwrap();
item_array_lock.insert(item, item);
});
}
// the scope will persist until all threads spawned inside it (with s.spawn) have completed, blocking the current thread,
// ensuring that any referenced data outlives all the threads
})
.unwrap();
// need to call .lock() here as well to get a reference to the HashMap
println!("{:?}", item_array.lock().unwrap());
Run in playground
1Except when the data has 'static lifetime, i.e. can exist for the entire lifetime of the program.
Here is very simple example of code based on source you have provieded:
use std::collections::HashMap;
use std::thread;
fn main() {
let item_array: HashMap<i32, i32> = HashMap::new();
let array: [i32; 3] = [0, 1, 2];
let mut handles = vec![];
let mutex = std::sync::Mutex::new(item_array);
let arc = std::sync::Arc::new(mutex);
for item in &array {
let item = item.to_owned();
let arc_cloned = std::sync::Arc::clone(&arc);
let th = thread::spawn(move || {
let mut guard = arc_cloned.lock().unwrap();
guard.insert(item, item);
});
handles.push(th);
}
for handle in handles {
handle.join().unwrap();
}
println!("{:?}", arc.lock().unwrap());
}
And you can play it here on rust playground

Primitive variable does not live long enough

There is an error in this piece of code:
let a: Vec<_> = (1..10).flat_map(|x| (1..x).map(|_| x)).collect();
The error message:
error[E0597]: `x` does not live long enough
--> src/main.rs:2:57
|
2 | let a: Vec<_> = (1..10).flat_map(|x| (1..x).map(|_| x)).collect();
| --- ^- - borrowed value needs to live until here
| | ||
| | |borrowed value only lives until here
| | borrowed value does not live long enough
| capture occurs here
But why?
Is is a primitive type, i.e. it should be cloned anyway.
What do I understand wrong?
This does not work because you capture x by reference when you do map(|_| x). x is not a variable local to the closure, so it is borrowed. To not borrow x, you must use the move keyword:
let a: Vec<_> = (1..10).flat_map(|x| (1..x).map(move |_| x)).collect();
But this is more idiomatic to write (for the same output):
use std::iter::repeat;
let b: Vec<_> = (2..10).flat_map(|x| repeat(x).take(x - 1)).collect();
Concerning the "why" question: some people could want to borrow a copyable data, so the capturing rules are the same:
Default: by reference,
With the move keyword: take the ownership.

Mutating the same external state with multiple closures [duplicate]

This question already has answers here:
What's the correct way to implement the equivalent of multiple mutable (statically allocated, statically dispatched, etc.) callbacks in Rust?
(1 answer)
How can callbacks with captured mutable variables be treated like normal mutable borrows?
(1 answer)
When I can use either Cell or RefCell, which should I choose?
(3 answers)
Closed 5 years ago.
I'm very new to learning Rust. Here's a condensed and silly code sample which I'm trying to compile:
fn do_something(read: &Fn() -> i32, write: &mut FnMut(i32)) {
if read() == 10 {
write(11);
}
}
fn print_11() {
let mut val = 10;
do_something(&|| val, &mut |n| val = n);
println!("Got {}", val);
}
The write closure borrows val mutably, and the read closure borrows it immutably. The compiler blocks this for this reason:
error[E0502]: cannot borrow `val` as mutable because it is also borrowed as immutable
--> src/main.rs:9:32
|
9 | do_something(&|| val, &mut |n| val = n);
| -- --- ^^^ --- - immutable borrow ends here
| | | | |
| | | | borrow occurs due to use of `val` in closure
| | | mutable borrow occurs here
| | previous borrow occurs due to use of `val` in closure
| immutable borrow occurs here
error[E0502]: cannot borrow `val` as mutable because it is also borrowed as immutable
--> src/main.rs:9:32
|
9 | do_something(&|| val, &mut |n| val = n);
| -- --- ^^^ --- - immutable borrow ends here
| | | | |
| | | | borrow occurs due to use of `val` in closure
| | | mutable borrow occurs here
| | previous borrow occurs due to use of `val` in closure
| immutable borrow occurs here
Is there an idiomatic way to create two closures which can read/write to the same variable? Is this a case for using something like Rc?

Resources