I'm just getting into Rust, so another beginner question... I've been doing stuff like the code below in C++ a lot. I'll use a closure as an inner helper function that captures local variables. But in Rust the rules don't let me do this. How would you get around this error?
It seems to me that finish() doesn't actually borrowmy_str until finishruns. But it seems Rust considers it borrowed when the closure is constructed, so the mutable borrow with push_str can't happen.
fn closure_capture_example() {
let mut my_str = String::new();
let finish = || -> i32 {
let n = my_str.parse().unwrap();
println!("finishing, parsing i32: {n}");
n
};
my_str.push_str("123");
let i = finish();
println!("done, i = {i}")
}
The error is:
error[E0502]: cannot borrow `my_str` as mutable because it is also borrowed as immutable
156 | let finish = || -> i32 {
| --------- immutable borrow occurs here
157 | let n = my_str.parse().unwrap();
| ------ first borrow occurs due to use of `my_str` in closure
...
161 | my_str.push_str("123");
| ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
162 | let i = finish();
| ------ immutable borrow later used here
Yes, that's how it works in Rust. You can think of closures as a compiler-provided struct where the fields are captures, and it gets constructed on the spot. They don't reborrow captures every call and release them between, or such.
+ my_str.push_str("123");
let finish = || -> i32 {
let n = my_str.parse().unwrap();
println!("finishing, parsing i32: {n}");
n
};
- my_str.push_str("123");
There's no silver bullet and the example is too simple to make very meaningful suggestions against (I just wouldn't have a closure for the OP). Generally you just have to treat capturing closures like other types of borrows. Taking arguments instead of capturing may be an option.
I guess my example a bit too simple there, since in the real code I can't move the push_str call like that, but I can follow your suggestion to pass the reference to the helper instead of capturing it.