Rust mut borrow fail in closure - rust

Here is my code
struct test_loop {
is_break: bool,
}
impl test_loop {
fn run_forever<F>(&mut self, mut f: F)
where
F: FnMut() -> (),
{
self.is_break = false;
loop {
f();
if self.is_break {
break;
}
}
}
fn breakit(&mut self) {
self.is_break = true;
}
}
fn main() {
let mut l = test_loop { is_break: false };
let f = || {
l.breakit();
};
l.run_forever(f);
}
The code is simple, and I don't want to skip calling l.breakit() in the closure. Now the compiler tells me there is a second mutable borrow problem:
error[E0499]: cannot borrow `l` as mutable more than once at a time
--> src/main.rs:26:5
|
23 | let f = || {
| -- first mutable borrow occurs here
24 | l.breakit();
| - first borrow occurs due to use of `l` in closure
25 | };
26 | l.run_forever(f);
| ^ - first borrow later used here
| |
| second mutable borrow occurs here
I used a RefCell to fix the compilation problem, but the thread still panics during run-time. Should I remove the l.xxx in the closure? Or there's some way to make the code act like it is running in C++ or another language?

if f() can change test_loop state, then it's natural to add this reference to its signature. This solves the second borrow problem.
fn run_forever<F>(&mut self, mut f: F)
where
F: FnMut(&mut Self) -> (),
{
// call f(self) instead of f()
}
// main
let f = |l: &mut test_loop| {
l.breakit();
};

Related

Reference should outlive closure parameter

So I've got the following structs
struct Item;
#[derive(Default)]
struct Resource<'a> {
_marker: std::marker::PhantomData<&'a ()>,
}
impl<'a> Resource<'a> {
// Note: item has to be borrowed for 'a
fn do_nothing(&mut self, item: &'a Item) {
let _ = item;
}
}
struct Context<'a> {
resource: Resource<'a>,
}
impl<'a> Context<'a> {
fn new() -> Self {
Self { resource: Resource::default() }
}
fn do_something(&mut self, item: &'a Item) {
self.resource.do_nothing(item);
}
}
And the following function that uses those sturcts.
fn do_stuff<F>(callback: F)
where
F: FnOnce(Context),
{
let ctx = Context::new();
(callback)(ctx);
}
When I try using this in the following manner
fn main() {
let item = Item;
do_stuff(|mut ctx| {
ctx.do_something(&item);
});
}
It gives the following compiler error:
error[E0597]: `item` does not live long enough
--> src/main.rs:40:27
|
39 | do_stuff(|mut ctx| {
| --------- value captured here
40 | ctx.do_something(&item);
| ------------------^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `item` is borrowed for `'static`
41 | });
42 | }
| - `item` dropped here while still borrowed
However, with my limited understanding of rust lifetimes, I'm not sure how to fix it. Item should outlive ctx as ctx only lives as long as do_stuff(?). Is there a way to tell the compiler that item lives longer then ctx?
One thing I highly recommend when dealing with lifetimes is to attempt to desugar lifetime elision as much as possible. The issue here actually happens in your definition of do_stuff:
fn do_stuff<F>(callback: F)
where
F: FnOnce(Context),
{
let ctx = Context::new();
(callback)(ctx);
}
which desugars to:
fn do_stuff<F>(callback: F)
where
F: FnOnce(Context<'static>),
{
let ctx = Context::new();
callback(ctx);
}
That 'static is what is causing the error. If you make the function generic over lifetime 'a the error goes away:
fn do_stuff<'a, F>(callback: F)
where
F: FnOnce(Context<'a>),
{
let ctx = Context::new();
callback(ctx);
}
playground

How can we solve this lifetime error occuring when conditionally returning a string slice?

The desired behaviour is if you can cut off 4 bytes cut and return 4 bytes, else if you can cut off 2 bytes cut and return 2 bytes, else return an error.
The methods cut, cut_alternative and cut_alternative_1 try to achieve this. The compiler error messages are listed below.
Why do all of these example methods fail to compile? In cut_alternative_1 the borrows are separated from each other while the error message is the same.
Can you give a workaround?
Playground link
struct StrWrapper<'s> {
content: &'s str,
}
impl<'s> StrWrapper<'s> {
fn cut(&mut self) -> Result<&str, ()> {
self.cut4()
.or(self.cut2())
}
fn cut_alternative(&mut self) -> Result<&str, ()> {
if let Ok(part) = self.cut4() {
Ok(part)
} else if let Ok(part) = self.cut2() {
Ok(part)
} else {
Err(())
}
}
fn cut_alternative_1(&'s mut self) -> Result<&'s str, ()> {
{
let part = self.cut4();
if part.is_ok() {
return part;
}
}
{
let part = self.cut2();
if part.is_ok() {
return part;
}
}
Err(())
}
fn cut2(&mut self) -> Result<&str, ()> {
if self.content.len() >= 2 {
let part = &self.content[..2];
self.content = &self.content[2..];
Ok(part)
} else {
Err(())
}
}
fn cut4(&mut self) -> Result<&str, ()> {
if self.content.len() >= 4 {
let part = &self.content[..4];
self.content = &self.content[4..];
Ok(part)
} else {
Err(())
}
}
}
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/parser.rs:210:17
|
208 | fn cut(&mut self) -> Result<&str, ()> {
| - let's call the lifetime of this reference `'1`
209 | self.cut4()
| ----
| |
| _________first mutable borrow occurs here
| |
210 | | .or(self.cut2())
| |_________________^^^^_______- returning this value requires that `*self` is borrowed for `'1`
| |
| second mutable borrow occurs here
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/parser.rs:216:34
|
213 | fn cut_alternative(&mut self) -> Result<&str, ()> {
| - let's call the lifetime of this reference `'1`
214 | if let Ok(part) = self.cut4() {
| ---- first mutable borrow occurs here
215 | Ok(part)
| -------- returning this value requires that `*self` is borrowed for `'1`
216 | } else if let Ok(part) = self.cut2() {
| ^^^^ second mutable borrow occurs here
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/parser.rs:230:24
|
207 | impl<'s> StrWrapper<'s> {
| -- lifetime `'s` defined here
...
224 | let part = self.cut4();
| ---- first mutable borrow occurs here
225 | if part.is_ok() {
226 | return part;
| ---- returning this value requires that `*self` is borrowed for `'s`
...
230 | let part = self.cut2();
| ^^^^ second mutable borrow occurs here
#Shepmaster commented a link to a similar question: Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
This question differs in two ways:
There are multiple mutable borrows instead of one unmutable and one mutable borrow.
I am unable to apply the workarounds in the answer to this problem right now. A workaround would be much appreciated.
The secret sauce in the HashMap solution is the use of contains_key(), which returns a bool that just doesn't carry the lifetime baggage. Likewise, the Vec solution involves using indices instead of slices in strategic places.
In your case the equivalent adaptation requires changing the signatures cut4() and cut2() to return Result<Range<usize>, ()>. Then you'd be able to write something like this:
fn cut(&mut self) -> Result<&str, ()> {
if let Ok(part) = self.cut4() {
Ok(&self.content[part])
} else if let Ok(part) = self.cut2() {
Ok(&self.content[part])
} else {
Err(())
}
}
fn cut2(&mut self) -> Result<Range<usize>, ()> {
if self.content.len() >= 2 {
let part = 0..2;
self.content = &self.content[2..];
Ok(part)
} else {
Err(())
}
}
// likewise for cut4
Playground
Another option would be to use interior mutability and make all of the functions accept &self:
use std::cell::Cell;
struct StrWrapper<'s> {
content: Cell<&'s str>,
}
impl<'s> StrWrapper<'s> {
fn cut(&self) -> Result<&str, ()> {
if let Ok(part) = self.cut4() {
Ok(part)
} else if let Ok(part) = self.cut2() {
Ok(part)
} else {
Err(())
}
}
fn cut2(&self) -> Result<&str, ()> {
if self.content.get().len() >= 2 {
let part = &self.content.get()[..2];
self.content.set(&self.content.get()[2..]);
Ok(part)
} else {
Err(())
}
}
// likewise for cut4
}
Playground (I was honestly surprised that this compiled, I've never tried to put a reference inside a Cell before.)
Finally, if neither of the above options is palatable for you, there is always unsafe:
fn cut(&mut self) -> Result<&str, ()> {
// Safety: slices returned by cut4() and cut2() must live at least as
// long as `self` (because the lifetime of `&str` returned is tied to the
// lifetime of `&self`). This is the case because cut2() and cut4() are
// bound by their signatures to return sub-slices of `self`, and we don't
// modify `self` between a successful call to cut*() and the return.
unsafe {
if let Ok((ptr, len)) = self.cut4().map(|s| (s.as_ptr(), s.len())) {
Ok(std::str::from_utf8(std::slice::from_raw_parts(ptr, len)).unwrap())
} else if let Ok((ptr, len)) = self.cut2().map(|s| (s.as_ptr(), s.len())) {
Ok(std::str::from_utf8(std::slice::from_raw_parts(ptr, len)).unwrap())
} else {
Err(())
}
}
}
Playground
If the unsafe voodoo looks scary, good - it should. The compiler won't help you if you slip up and make a mistake, so that kind of thing should be used only as a last resort. I think the above code is correct because it basically works the same way as the range version, it just converts the slices to their constituent parts after they've been created. But any time someone refactors the code you'll be wondering if a crash or, worse, a silent UB is lurking around the corner.
In case it's not already obvious, my recommendation would be approach #1.

Edit RefCell in closure

I want to store a closure in struct that implements Clone, so i'm code this:
use std::rc::Rc;
type Closure = Box<dyn Fn() -> ()>;
#[derive(Clone)]
struct A {
closure: Option<Rc<Closure>>,
}
impl A {
pub fn new() -> A {
A { closure: None }
}
pub fn closure(&self) -> Option<Rc<Closure>> {
self.closure.clone()
}
pub fn set_closure(&mut self, closure: Closure) -> &mut Self {
self.closure = Some(Rc::new(closure));
self
}
}
fn main() {
let mut a: A = A::new();
a.set_closure(Box::new(|| -> () { println!("Works fine!") }));
(a.closure().unwrap())();
}
Now I want to test this code by borrowing a variable of current scope. It's important to keep a reference in main function, because i need to use it after.
I code this:
use std::cell::RefCell;
fn main() {
let mut a: A = A::new();
let value: Rc<RefCell<i8>> = Rc::new(RefCell::new(0));
println!("Value = {}", value.borrow());
a.set_closure(Box::new(|| -> () {
*value.borrow_mut() = 1;
}));
(a.closure().unwrap())();
println!("New value = {}", value.borrow());
}
But I get this error:
Compiling playground v0.0.1 (/playground)
error[E0597]: `value` does not live long enough
--> src/main.rs:34:38
|
34 | a.set_closure(Box::new(|| -> () { *value.borrow_mut() = 1; }));
| ---------------------^^^^^---------------------
| | | |
| | | borrowed value does not live long enough
| | value captured here
| cast requires that `value` is borrowed for `'static`
...
38 | }
| - `value` dropped here while still borrowed
Would anyone know what I need to do please.
Thank you for your reply in advance.
Rcs are shared by cloning, which increments their reference count. But you pass a reference to it to the closure, which is perhaps defeating the point of using an Rc in the first place. As the error says, the closure is holding a reference to value after value is dropped.
You probably intended to write something like this, which clones the Rc and moves the clone into the closure:
let cloned_value = value.clone();
a.set_closure(Box::new(move || *cloned_value.borrow_mut() = 1));
Or (my preference) avoiding introducing a new binding in the outer scope:
a.set_closure(Box::new({
let value = value.clone();
move || *value.borrow_mut() = 1
}));

how to refactor rust code to resolve borrow that reference parent in closure?

trait OnUpdate {
fn on_update(&mut self, x: &i32);
}
struct Foo {
field: i32,
cbs: Vec<Box<OnUpdate>>,
}
struct Bar {
foos: Vec<Foo>,
}
impl Bar {
fn call_foo_cb(&mut self) {
self.foos
.iter_mut()
.for_each(|foo| foo.cbs.iter_mut().for_each(|cb| cb.on_update(&self.value(*foo)))) // compile error see below
// .for_each(|foo| foo.cbs.iter_mut().for_each(|cb| cb.on_update(&10))) // works
}
fn value(&self, foo: Foo) -> i32 {
foo.field + self.foos.len() as i32 // pretend some calculation based on the current foo and self
}
}
The above code is to demonstrate my problem. I am new to rust and I am wondering what is the best way to refactor in idiomatic rust way.
Thanks in advance.
--> src/lib.rs:348:23
|
346 | self.foos
| --------- mutable borrow occurs here
347 | .iter_mut()
348 | .for_each(|foo| foo.cbs.iter_mut().for_each(|cb| cb.on_update(&self.value(*foo))))
| -------- ^^^^^ immutable borrow occurs here ---- second borrow occurs due to use of `self` in closure
| |
| mutable borrow later used by call
Its easier for me to reason about this with for loops, so consider this equivalent:
for foo in &mut self.foos {
for cb in &mut foo.cbs {
cb.on_update(&self.value(foo));
}
}
If the calculated value doesn't depend on cb, then it can be moved out of the loop:
for foo in &mut self.foos {
let x = self.value(foo);
for cb in &mut foo.cbs {
cb.on_update(&x);
}
}
And then, you can change out the mutable loop for one using indexes to avoid creating a mutable borrow until later:
for i in 0..self.foos.len() {
let x = self.value(&self.foos[i]);
for cb in &mut self.foos[i].cbs {
cb.on_update(&x);
}
}
This code assumes that the value function actually takes the Foo by reference since its not Copy or Clone.

How can I peek into a vector and pop if a condition is met?

I want to retrieve an element from a vector if a condition on that element is true.
fn draw() -> Option<String> {
let mut v: Vec<String> = vec!["foo".to_string()];
let t: Option<String>;
let o = v.last();
// t and v are actually a fields in a struct
// so their lifetimes will continue outside of draw().
match o {
Some(ref e) => {
if check(e) {
t = v.pop();
t.clone()
} else {
None
}
}
None => None,
}
}
fn check(e: &String) -> bool {
true
}
fn main() {}
playground
This results in the error:
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> src/main.rs:12:21
|
4 | let o = v.last();
| - immutable borrow occurs here
...
12 | t = v.pop();
| ^ mutable borrow occurs here
...
20 | }
| - immutable borrow ends here
Which I sort of understand, however I don't see a way to end the borrow (without using clone()).
Borrows are lexical, so v has the life-time of the whole function. If one can reduce the scope, one can use last() and pop(). One way to do this is a functional-style map:
let mut v: Vec<String> = vec!["foo".to_string()];
if v.last().map_or(false, check) {
v.pop()
} else {
None
}

Resources