Closure may outlive the current function - rust

I am just starting to learn Rust. For this purpose I am rewriting my C++ project in Rust, but the biggest problems are lifetimes of closures and such.
I created a absolute minimal scenario of my problem seen here and below:
use std::sync::Arc;
use std::cell::{RefCell, Cell};
struct Context {
handler: RefCell<Option<Arc<Handler>>>,
}
impl Context {
pub fn new() -> Arc<Context> {
let context = Arc::new(Context{
handler: RefCell::new(None),
});
let handler = Handler::new(context.clone());
(*context.handler.borrow_mut()) = Some(handler);
context
}
pub fn get_handler(&self) -> Arc<Handler> {
self.handler.borrow().as_ref().unwrap().clone()
}
}
struct Handler {
context: Arc<Context>,
clickables: RefCell<Vec<Arc<Clickable>>>,
}
impl Handler {
pub fn new(context: Arc<Context>) -> Arc<Handler> {
Arc::new(Handler{
context: context,
clickables: RefCell::new(Vec::new()),
})
}
pub fn add_clickable(&self, clickable: Arc<Clickable>) {
self.clickables.borrow_mut().push(clickable);
}
pub fn remove_clickable(&self, clickable: Arc<Clickable>) {
// remove stuff ...
}
}
struct Clickable {
context: Arc<Context>,
callback: RefCell<Option<Box<Fn()>>>,
}
impl Clickable {
pub fn new(context: Arc<Context>) -> Arc<Clickable> {
let clickable = Arc::new(Clickable{
context: context.clone(),
callback: RefCell::new(None),
});
context.get_handler().add_clickable(clickable.clone());
clickable
}
pub fn remove(clickable: Arc<Clickable>) {
clickable.context.get_handler().remove_clickable(clickable);
}
pub fn set_callback(&self, callback: Option<Box<Fn()>>) {
(*self.callback.borrow_mut()) = callback;
}
pub fn click(&self) {
match *self.callback.borrow() {
Some(ref callback) => (callback)(),
None => (),
}
}
}
struct Button {
context: Arc<Context>,
clickable: Arc<Clickable>,
}
impl Button {
pub fn new(context: Arc<Context>) -> Arc<Button> {
let clickable = Clickable::new(context.clone());
let button = Arc::new(Button{
context: context,
clickable: clickable.clone(),
});
let tmp_callback = Box::new(|| {
button.do_stuff();
});
clickable.set_callback(Some(tmp_callback));
button
}
pub fn do_stuff(&self) {
// doing crazy stuff
let mut i = 0;
for j in 0..100 {
i = j*i;
}
}
pub fn click(&self) {
self.clickable.click();
}
}
impl Drop for Button {
fn drop(&mut self) {
Clickable::remove(self.clickable.clone());
}
}
fn main() {
let context = Context::new();
let button = Button::new(context.clone());
button.click();
}
I just don't know how to pass references in closures.
Another ugly thing is that my Handler and my Context need each other. Is there a nicer way to to create this dependency?

Going off your initial code
pub fn new(context: Arc<Context>) -> Arc<Button> {
let clickable = Clickable::new(context.clone());
let button = Arc::new(Button{
context: context,
clickable: clickable.clone(),
});
let tmp_callback = Box::new(|| {
button.do_stuff();
});
clickable.set_callback(Some(tmp_callback));
button
}
First off, let's note the error you're getting
error[E0373]: closure may outlive the current function, but it borrows `button`, which is owned by the current function
--> src/main.rs:101:37
|
101 | let tmp_callback = Box::new(|| {
| ^^ may outlive borrowed value `button`
102 | button.do_stuff();
| ------ `button` is borrowed here
|
help: to force the closure to take ownership of `button` (and any other referenced variables), use the `move` keyword, as shown:
| let tmp_callback = Box::new(move || {
Noting the help block at the bottom, you need to use a move closure, because when the new function ends, the button variable on the stack will go out of scope. The only way to avoid that is to move ownership of it to the callback itself. Thus you'd change
let tmp_callback = Box::new(|| {
to
let tmp_callback = Box::new(move || {
Now, you'd get a second error:
error[E0382]: use of moved value: `button`
--> src/main.rs:107:9
|
102 | let tmp_callback = Box::new(move || {
| ------- value moved (into closure) here
...
107 | button
| ^^^^^^ value used here after move
|
= note: move occurs because `button` has type `std::sync::Arc<Button>`, which does not implement the `Copy` trait
And the error here may be a little clearer. You're trying to move ownership of the button value into the callback closure, but you also use it inside the body of the new function when you return it, and you can't have two different things trying to own the value.
The solution to that is hopefully what you'd guess. You have to make a copy that you can take ownership of. You'll want to then change
let tmp_callback = Box::new(move || {
button.do_stuff();
to
let button_clone = button.clone();
let tmp_callback = Box::new(move || {
button_clone.do_stuff();
Now you've created a new Button object, and returned an Arc for the object itself, while also giving ownership of a second Arc to the callback itself.
Update
Given your comment, there is indeed an issue here of cyclic dependencies, since your Clickable object holds ownership of a reference to Button, while Button holds ownership of a reference to Clickable. The easiest way to fix this here would be to update that code a third time, from
let button_clone = button.clone();
let tmp_callback = Box::new(move || {
button_clone.do_stuff();
to
let button_weak = Arc::downgrade(&button);
let tmp_callback = Box::new(move || {
if let Some(button) = button_weak.upgrade() {
button.do_stuff();
}
});
so the Clickable will only hold a weak reference to the Button, and if the Button is no longer referenced, the callback will be a no-op.
You'd also probably want to consider making clickables a list of Weak references instead of strong references, so you can remove items from it when the item they reference is removed.

Related

Create vector of trait objects

I am trying to create a vector of trait objects but I'm getting a type mismatch. I also tried using .map() instead of a for loop but had the same problem. This is a minimal version of my real code, I realise this example doesn't require the use of trait objects but my real code does since there will be types other than Link in the List, which also implement Speak. How can I create a Vec with the correct type so I can pass it to trait_objects?
use std::fs;
fn main() {
// let links = fs::read_dir("my_dir").unwrap();
// let links: Vec<Box<dyn Speak>> = links
// .map(|file| {
// let myfile = file.unwrap();
// let href = myfile.path().to_str().unwrap();
// Box::new(Link { attr: href })
// })
// .collect();
let links = Vec::new();
for entry in fs::read_dir("my_dir").unwrap() {
let myfile = entry.unwrap();
let href = myfile.path().to_str().unwrap();
links.push(Box::new(Link { attr: href }));
}
let link_objects = ListOfTraitObjects {
trait_objects: links,
};
for link in link_objects.trait_objects.iter() {
println!("{}", link.speak());
}
}
trait Speak {
fn speak(&self) -> String;
}
struct ListOfTraitObjects {
trait_objects: Vec<Box<dyn Speak>>,
}
struct Link<'a> {
attr: &'a str,
}
impl Speak for Link<'_> {
fn speak(&self) -> String {
self.attr.to_string()
}
}
There are several issues with your code. The first is that you're creating a Vec<Box<Link>> instead of a Vec<Box<Speak>>. By default Box::new (foo) creates a box of the same type as foo. If you want a box of some trait implemented by foo, you need to be explicit:
links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
Playground
However this gives two new errors:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:7:20
|
7 | let href = myfile.path().to_str().unwrap();
| ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
8 | links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
| ----------------------------- cast requires that borrow lasts for `'static`
error[E0596]: cannot borrow `links` as mutable, as it is not declared as mutable
--> src/lib.rs:8:9
|
4 | let links = Vec::new();
| ----- help: consider changing this to be mutable: `mut links`
...
8 | links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
The first error is because your Link struct borrows a string from entry, but entry only lives as long as the current loop iteration. Even though the error states that the cast requires a 'static lifetime, you would get a similar error if you were simply trying to build a Vec<Link> without casting (playground). You need to change the definition of your Link struct to contain an owned string:
struct Link {
attr: String,
}
impl Speak for Link {
fn speak(&self) -> String {
self.attr.clone()
}
}
The second error is easier and can be fixed simply by following the compiler suggestion and replacing let links = … with let mut links = ….
Full working example:
use std::fs;
fn main() {
let mut links = Vec::new();
for entry in fs::read_dir("my_dir").unwrap() {
let myfile = entry.unwrap();
let href = myfile.path().to_str().unwrap().to_string();
links.push(Box::new(Link { attr: href }) as Box::<dyn Speak>);
}
let link_objects = ListOfTraitObjects {
trait_objects: links,
};
for link in link_objects.trait_objects.iter() {
println!("{}", link.speak());
}
}
trait Speak {
fn speak(&self) -> String;
}
struct ListOfTraitObjects {
trait_objects: Vec<Box<dyn Speak>>,
}
struct Link {
attr: String,
}
impl Speak for Link {
fn speak(&self) -> String {
self.attr.clone()
}
}
Playground
The same fixes can be applied to your iterator-based solution:
let links = fs::read_dir("my_dir").unwrap();
let links: Vec<_> = links
.map(|file| {
let myfile = file.unwrap();
let href = myfile.path().to_str().unwrap().to_string();
Box::new(Link { attr: href }) as Box<dyn Speak>
})
.collect();
Playground

Borrowing errors whilst mutating in for loop

I am having issues with the borrow checker and temporary values in rust.
I'm hoping to find a solution to this specific problem as well as better learn how to handle this kind of situation in the future. I originally started off with a for_each but ran into issues terminating early.
I considered moving the logic of check_foo into update_foo, however this wouldn't work well for my real world solution; the MRE focuses on the compilation issues vs what I'm trying to achieve in the whole program.
Edit: Is there a way for me to achieve this in a purely functional approach?
I want to iterate over a range of numbers, updating a Vec<Foo> and potentially returning early with a value. Below is a minimal reproducible example of my code with the same errors:
I tried tried implementing as:
fn run<'a>(mut foos: Vec<Foo>) -> Vec<&'a u32> {
let mut bar: Vec<&u32> = vec![];
for num in 0..10 {
for foo in &mut foos {
update_foo(foo);
let checked_foo = check_foo(&foo);
if checked_foo.is_empty() {
bar = checked_foo;
break;
}
}
}
bar
}
/* `fn update_foo` and `fn check_foo` definitions same as below */
but this resulted in:
21 | for foo in &mut foos {
| ^^^^^^^^^ `foos` was mutably borrowed here in the previous iteration of the loop
To overcome this I added the use of Rc and RefCell to allow me to iterate over a reference whilst still being able to mutate:
#[derive(Clone, Debug, PartialEq)]
pub struct Foo {
updated: bool,
}
fn run<'a>(foos: Vec<Rc<RefCell<Foo>>>) -> Vec<&'a u32> {
let mut bar: Vec<&u32> = vec![];
for num in 0..10 {
for foo in &foos {
update_foo(&mut foo.borrow_mut());
let checked_foo = check_foo(&foo.borrow());
if checked_foo.is_empty() {
bar = checked_foo;
break;
}
}
}
bar
}
fn update_foo(foo: &mut Foo) {
foo.updated = true
}
fn check_foo(foo: &Foo) -> Vec<&u32> {
if foo.updated {
vec![&0, &1, &2]
} else {
vec![]
}
}
which results in:
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:33:5
|
26 | let checked_foo = check_foo(&foo.borrow());
| ------------ temporary value created here
...
33 | bar
| ^^^ returns a value referencing data owned by the current function
error[E0515]: cannot return value referencing function parameter `foos`
--> src/main.rs:33:5
|
23 | for foo in &foos {
| ----- `foos` is borrowed here
...
33 | bar
| ^^^ returns a value referencing data owned by the current function
For more information about this error, try `rustc --explain E0515`.
I'm not entirely sure what you plan to do with this, but it seems to me like a few of the references you're using should be owned. Here's what I came up with.
#[derive(Clone, Debug, PartialEq)]
pub struct Foo {
updated: bool,
}
fn run(foos: &mut Vec<Foo>) -> Vec<u32> {
let mut bar: Vec<u32> = vec![];
for num in 0..10 {
for foo in foos.iter_mut() {
update_foo(foo);
let checked_foo = check_foo(&foo);
if checked_foo.is_empty() {
bar = checked_foo;
break;
}
}
}
bar
}
fn update_foo(foo: &mut Foo) {
foo.updated = true
}
fn check_foo(foo: &Foo) -> Vec<u32> {
if foo.updated {
vec![0, 1, 2]
} else {
vec![]
}
}
References should be used when you expect some other struct to own the objects you are referring to, but here you're constructing new vectors with new data, so you should keep the elements owned.

Can't get async closure to work with Warp::Filter

I am trying to get an async closure working in the and_then filter from Warp.
This is the smallest example I could come up with where I am reasonably sure I didn't leave any important details out:
use std::{convert::Infallible, sync::Arc, thread, time};
use tokio::sync::RwLock;
use warp::Filter;
fn main() {
let man = Manifest::new();
let check = warp::path("updates").and_then(|| async move { GetAvailableBinaries(&man).await });
}
async fn GetAvailableBinaries(man: &Manifest) -> Result<impl warp::Reply, Infallible> {
Ok(warp::reply::json(&man.GetAvailableBinaries().await))
}
pub struct Manifest {
binaries: Arc<RwLock<Vec<i32>>>,
}
impl Manifest {
pub fn new() -> Manifest {
let bins = Arc::new(RwLock::new(Vec::new()));
thread::spawn(move || async move {
loop {
thread::sleep(time::Duration::from_millis(10000));
}
});
Manifest { binaries: bins }
}
pub async fn GetAvailableBinaries(&self) -> Vec<i32> {
self.binaries.read().await.to_vec()
}
}
I am using:
[dependencies]
tokio = { version = "0.2", features = ["full"] }
warp = { version = "0.2", features = ["tls"] }
The error is:
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src/main.rs:9:48
|
9 | let check = warp::path("updates").and_then(|| async move { GetAvailableBinaries(&man).await });
| -------- ^^^^^^^^^^^^^ ------------------------------------ closure is `FnOnce` because it moves the variable `man` out of its environment
| | |
| | this closure implements `FnOnce`, not `Fn`
| the requirement to implement `Fn` derives from here
After making Manifest implement Clone, you can fix the error by balancing when the manifest object is cloned:
fn main() {
let man = Manifest::new();
let check = warp::path("updates").and_then(move || {
let man = man.clone();
async move { get_available_binaries(&man).await }
});
warp::serve(check);
}
This moves man into the closure passed to and_then, then provides a clone of man to the async block each time the closure is executed. The async block then owns that data and can take a reference to it without worrying about executing the future after the data has been deallocated.
I'm not sure this is what you're going for, but this solution builds for me:
use std::{convert::Infallible, sync::Arc, thread, time};
use tokio::sync::RwLock;
use warp::Filter;
fn main() {
let man = Manifest::new();
let check = warp::path("updates").and_then(|| async { GetAvailableBinaries(&man).await });
}
async fn GetAvailableBinaries(man: &Manifest) -> Result<impl warp::Reply, Infallible> {
Ok(warp::reply::json(&man.GetAvailableBinaries().await))
}
#[derive(Clone)]
pub struct Manifest {
binaries: Arc<RwLock<Vec<i32>>>,
}
impl Manifest {
pub fn new() -> Manifest {
let bins = Arc::new(RwLock::new(Vec::new()));
thread::spawn(move || async {
loop {
thread::sleep(time::Duration::from_millis(10000));
//mutate bins here
}
});
Manifest { binaries: bins }
}
pub async fn GetAvailableBinaries(&self) -> Vec<i32> {
self.binaries.read().await.to_vec()
}
}
The move here is the reason the compiler gave a warning regarding the signature: let check = warp::path("updates").and_then(|| async move { GetAvailableBinaries(&man).await });. This means that everything referenced in this closure will be moved into the context of the closure. In this case, the compiler can't guarantee the closure to be Fn but only FnOnce meaning that the closure can only be guaranteed to execute once.

still trying to reimplement a c++ timerqueue in rust

more on reimplementing c++ timerqueue in rust
This code tries to create a vec of tasks and run them on a different thread. Still cannot compile it. I am at the point of typing words at random into random locations to see if it helps , 'static here, move there dyn sync ,....
I think if I were to see a working version I would be able to work out why I was stuck. But I cannot make it go.
heres the complete code
use std::thread;
use std::time::Instant;
fn main() {
let x = || {
println!("hello");
};
let y = || {
println!("hello2");
};
let mut tq = TimerQueue::new();
tq.set(Box::new(x), String::from("yo"), Instant::now());
tq.set(Box::new(y), String::from("yo"), Instant::now());
tq.thr();
}
pub struct TimerQueueItem {
when: Instant,
name: String,
what: QIFunc,
}
type QIFunc = Box<dyn Fn() -> () + Send>;
struct TimerQueue {
queue: Vec<TimerQueueItem>,
}
impl TimerQueue {
fn thr(&mut self) -> () {
thread::spawn(move || {
self.runq();
});
}
fn set(&mut self, f: QIFunc, n: String, when: Instant) {
let qi = TimerQueueItem {
what: f,
name: n,
when: when,
};
self.queue.push(qi);
}
fn new() -> TimerQueue {
TimerQueue { queue: Vec::new() }
}
fn runq(&mut self) -> () {
for qi in self.queue.iter() {
(qi.what)();
}
}
}
all sorts of errors all pointing at the same place
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src\main.rs:31:23
|
31 | thread::spawn(move || {
| _______________________^
32 | | self.runq();
33 | | });
| |_________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 30:5...
--> src\main.rs:30:5
this one seems particularly designed to confuse
= note: expected `&mut TimerQueue`
found `&mut TimerQueue`
Your TimerQueue object is stored on the stack of the main thread. Because Rust cannot guarantee that the new thread will finish before the main one, it has imposed some restrictions on how you can pull off recreating your timerqueue.
I actually found a simple fix. Basically, I removed the thr method and moved its body into main.
use std::thread;
use std::time::Instant;
fn main() {
let x = || {
println!("hello");
};
let y = || {
println!("hello2");
};
let mut tq = TimerQueue::new();
tq.set(Box::new(x), String::from("yo"), Instant::now());
tq.set(Box::new(y), String::from("yo"), Instant::now());
thread::spawn(move || {
tq.runq();
});
thread::sleep_ms(1000);
}
pub struct TimerQueueItem {
when: Instant,
name: String,
what: QIFunc,
}
type QIFunc = Box<dyn Fn() -> () + Send>;
struct TimerQueue {
queue: Vec<TimerQueueItem>,
}
impl TimerQueue {
fn set(&mut self, f: QIFunc, n: String, when: Instant) {
let qi = TimerQueueItem {
what: f,
name: n,
when: when,
};
self.queue.push(qi);
}
fn new() -> TimerQueue {
TimerQueue { queue: Vec::new() }
}
fn runq(&mut self) -> () {
for qi in self.queue.iter() {
(qi.what)();
}
}
}
Note: I added the
thread::sleep_ms(1000);
which ensures that the main thread will last as long as the spawned thread - at least in this example, other scenarios might have the new thread require more time. If you want to pause the main thread until the spawned one completes (regardless of how long the spawned one takes), you can replace
thread::spawn(move || {
tq.runq();
});
thread::sleep_ms(1000);
with
let thread_handle = thread::spawn(move || {
tq.runq();
});
thread_handle.join();
For reference, my cargo version is 1.41.0
Instead of thr(&mut self), write thr(mut self).
(mut because runq wants a mutable reference. It might not need to though.)
You can't transfer ownership of the TimerQueue to the new thread with just a reference. When you "move" something into a closure, you transfer ownership there. On the other hand, if you didn't move (i.e. left the move keyword out), you couldn't ensure that self would live long enough.
A C++ analogy to this would be
// BAD: v may go out of scope in the main
// thread before the new thread completes.
// Also facilitates data races.
std::vector<...> v;
std::thread([&v] () {
// use/modify v
});
// BETTER: v is moved to be "owned" by the
// closure, so it will certainly live as long as the
// thread is alive.
std::vector<...> v;
std::thread([v=std::move(v)] () mutable {
// use/modify v
})
There's really no such thing as a member function that takes this as moved in C++, but there is in Rust. You can think of it as a static class method that looks like this instead:
static void thr(TimerQueue &&tq);
// called as
TimerQueue::thr(std::move(tq));
Of course, that's not identical to the Rust version in many ways, but hopefully this helps you understand what's going on.
That error message is certainly unhelpful. Not sure what's going on there.

Handle multiple mutable references borrowed by different structs

I am relatively new to Rust and wanted to learn it by building a game with Piston.
There I have a Renderer struct that renders the scene and a main loop that handles game-logic events. They both need a mutable borrow and I understand that multiple borrows can lead to undefined behaviour, but I don't understand how it can in my case, since I always use the object in different scopes and in the same thread.
I had a look at this question and feel like I am supposed to use Rc and/or RefCell to solve this, but this seems too extreme. I also don't think I need ownership in the renderer (or do I, then why?), because the renderer lives shorter than the main loop.
Another solution would be to pass the mutable object every time it is needed, but in the real case this is almost for every function and I come from Java/C++ where the below code worked.
struct Renderer<'a> {
w: &'a mut Window,
}
impl<'a> Renderer<'a> {
fn render(&mut self) {
let w = &mut self.w;
// complex render operation needing the window mutably
}
}
struct Window {
//...
}
impl Window {
fn poll_event(&mut self) {
//some internal code of piston
}
}
fn main() {
let mut w = Window {};
let mut renderer = Renderer { w: &mut w };
loop {
{
//first event handling
w.poll_event();
}
{
//AFTERWARDS rendering
renderer.render();
}
}
}
With the error:
error[E0499]: cannot borrow `w` as mutable more than once at a time
--> src/main.rs:29:13
|
24 | let mut renderer = Renderer { w: &mut w };
| - first mutable borrow occurs here
...
29 | w.poll_event();
| ^ second mutable borrow occurs here
...
36 | }
| - first borrow ends here
My Rc approach compiles fine, but seems over the top:
use std::rc::Rc;
struct Renderer {
w: Rc<Window>,
}
impl Renderer {
fn render(&mut self) {
let w = Rc::get_mut(&mut self.w).unwrap();
// complex render operation needing the window mutably
}
}
struct Window {
//...
}
impl Window {
fn poll_event(&mut self) {
//some internal code of piston
}
}
fn main() {
let mut w = Rc::new(Window {});
let mut renderer = Renderer { w: w.clone() };
loop {
{
//first event handling
Rc::get_mut(&mut w).unwrap().poll_event();
}
{
//AFTERWARDS rendering
renderer.render();
}
}
}
All I actually need to do is delaying the &mut. This works with Rc but I don't need ownership - so all the unwrap stuff will never fail since I (can) use it in different scopes.
Can this predicament be resolved or am I forced to use Rc in this case?
If there is a more "Rusty" way of doing this, please let me know.

Resources