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.
Related
Nested iteration combined with side-effects don't seem to work very well with Rust iterators. Here is an example:
fn main(){
let v1=vec![1];
let v2=vec![3];
let mut v3=vec![];
v1.iter().map(|x|{
v2.iter().map(|y|{
v3.push(*y);
})
});
}
This results in the following error:
error: captured variable cannot escape `FnMut` closure body
--> src/main.rs:6:5
|
4 | let mut v3=vec![];
| ------ variable defined here
5 | v1.iter().map(|x|{
| - inferred to be a `FnMut` closure
6 | / v2.iter().map(|y|{
7 | | v3.push(*y);
| | -- variable captured here
8 | | })
| |______^ returns a reference to a captured variable which escapes the closure body
I assume the problem has something to do with the laziness of iterators and a conflict between the two closures. What is causing the error? And how do I fix it?
today I tried to write this MusicGuesser with GTK for fun and got this error:
error[E0507]: cannot move out of `guess`, a captured variable in an `Fn` closure
--> src/main.rs:63:32
|
15 | let mut guess = Arc::new(get_guess());
| --------- captured outer variable
16 |
17 | app.connect_activate(move |app| {
| ---------- captured by this `Fn` closure
...
63 | button.connect_clicked(move |_| {
| ^^^^^^^^ move out of `guess` occurs here
64 | let mut guess = Arc::clone(&guess);
| -----
| |
| variable moved due to use in closure
| move occurs because `guess` has type `Arc<Vec<std::string::String>>`, which does not implement the `Copy` trait
I found some same questions about this error, but I didn't understand them. There is source code: https://pastebin.com/1pNxEiB5
let guess = Arc::new(get_guess());
let cloned_guess = Arc::clone(&guess);
// ...
app.connect_activate(move |app| {
// ...
button.connect_clicked(move |_| {
let guess = cloned_guess;
// ...
If you use something in a move || closure, you move it into that closure. That means in your case you move the entire outer guess object in.
So you need to clone first, and then only move the cloned object in.
You will hit the next problem soon, though, because the content of Arc is always immutable. In Rust, you can never have multiple mutable references to the same thing. So in order to modify your guess, you will have to create interior mutability via Mutex or similar.
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.
I'm getting
error[E0373]: closure may outlive the current function, but it borrows row_nr, which is owned by the current function
I would not expect this, since row_nr is a u32, so I'd expect it to be copied rather than moved:
fn get_neighbours(values: &Vec<Vec<u32>>, row: usize, col: usize) -> Vec<u32> {
vec![
values.get(row - 1).and_then(|cols| cols.get(col)),
values.get(row).and_then(|cols| cols.get(col - 1)),
values.get(row).and_then(|cols| cols.get(col + 1)),
values.get(row + 1).and_then(|cols| cols.get(col)),
].into_iter().filter_map(|value_opt| value_opt.map(|value| *value)).collect()
}
fn get_points(values: Vec<Vec<u32>>) -> Vec<(u32, Vec<u32>)> {
values
.iter()
.enumerate()
.flat_map(|(row_nr, columns)| {
columns.iter().enumerate().map(|(column_nr, height)| {
let neighbours = get_neighbours(&values, row_nr, column_nr);
(*height, neighbours)
})
}).collect()
}
Full error message:
--> src/lib.rs:16:44
|
16 | columns.iter().enumerate().map(|(column_nr, height)| {
| ^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `row_nr`
17 | let neighbours = get_neighbours(&values, row_nr, column_nr);
| ------ `row_nr` is borrowed here
|
note: closure is returned here
--> src/lib.rs:16:13
|
16 | / columns.iter().enumerate().map(|(column_nr, height)| {
17 | | let neighbours = get_neighbours(&values, row_nr, column_nr);
18 | | (*height, neighbours)
19 | | })
| |______________^
help: to force the closure to take ownership of `row_nr` (and any other referenced variables), use the `move` keyword
|
16 | columns.iter().enumerate().map(move |(column_nr, height)| {
| ++++
See also on the Rust playground.
Now, the error suggest using move, but that becomes problematic because I'd only like to pass a reference to the values Vec (which I don't think should outlive the closure, because get_neighbours takes u32s from that Vec and thus should make copies too, I think?).
I presume I'm misunderstanding lifetimes here. I'd appreciate any insights on what I'm misinterpreting. I looked at a couple of related questions, but they seem to either resolve it using a move (which, as mentioned above, I think I should (be able to) avoid?), or have multiple borrow checker issues, making it hard for me to understand which applies ones to me (e.g. this answer).
I would not expect this, since row_nr is a u32, so I'd expect it to be copied rather than moved
This expectation is correct, assuming it were moved in the first place. In this case it's not moved, it's borrowed, because by default closures borrow values from their environment. To request a move, which will for u32 indeed result in a copy, you need to use the move keyword explicitly.
As you discovered, when you just use move, you also move values, which doesn't compile and is anyway not what you want. The standard Rust idiom to move only one value into the closure is to use move and explicitly borrow the captured variables you don't want moved (in yout case values). For example, this compiles:
.flat_map(|(row_nr, columns)| {
columns.iter().enumerate().map({
let values = &values;
move |(column_nr, height)| {
let neighbours = get_neighbours(values, row_nr, column_nr);
(*height, neighbours)
}
})
})
Playground
As for your titular question of why may a closure outlive the current function: Note that the "current function" in the error message refers to the outer closure, the one passed to flat_map(). Since the inner closure becomes part of the iterator returned by map(), and the outer closure immediately returns that iterator, it is trivially true that the inner closure does outlive the "current function" and that it cannot be allowed to borrow either row_nr or columns. (But borrowing values is perfectly fine because values outlives both closures.)
I have a struct containing two fields and I want to modify one field (mutable borrow) using another field (immutable borrow), but I get an error from the borrow checker.
For instance, the following code:
struct Struct {
field1: Vec<i32>,
field2: Vec<i32>,
}
fn main() {
let mut strct = Struct {
field1: vec![1, 2, 3],
field2: vec![2, 3, 4],
};
strct.field1.retain(|v| !strct.field2.contains(v));
println!("{:?}", strct.field1);
}
gives the following error:
error[E0502]: cannot borrow `strct.field1` as mutable because it is also borrowed as immutable
--> src/main.rs:12:5
|
12 | strct.field1.retain(|v| !strct.field2.contains(v));
| ^^^^^^^^^^^^^------^---^^-----^^^^^^^^^^^^^^^^^^^^
| | | | |
| | | | first borrow occurs due to use of `strct` in closure
| | | immutable borrow occurs here
| | immutable borrow later used by call
| mutable borrow occurs here
What are the Rust ways of updating one field using another from within a closure?
Usually the borrow checker can distinguish between the different fields of a structure, but this doesn't work within closures (lambdas).
Instead, borrow the second field outside the closure:
let field2 = &strct.field2;
strct.field1.retain(|v| !field2.contains(v));
This recent blog post shows a very useful pattern for this kind of problem:
Sometimes, when I want to be very precise, I will write closures in a stylized way that makes it crystal clear what they are capturing. Instead of writing |v| ..., I first introduce a block that creates a lot of local variables, with the final thing in the block being a move closure (move closures take ownership of the things they use, instead of borrowing them from the creator). This gives complete control over what is borrowed and how. In this case, the closure might look like:
In other words, the borrows are defined right with the closure and moved into the closure. This makes it totally clear that their purpose is to provide the closure with borrowed values. In context of the original question the pattern would look like this:
strct.field1.retain({
let field2 = &strct.field2;
move |v| !field2.contains(v)
});
A nice property of this code is that the borrow of field2 does not stick around after it is no longer used.