Pass around a struct to be mutated by a Fn closure

Here is a contrived example of a code where I am stuck

struct Foo {
    bar: Option<String>,
}

fn baz(foo_arg: &mut Foo) {
    // Additional code that includes declaration of some_local_var
    some_local_var.on_event(|| {  // Fn closure
        foo_arg.bar = Some(ruh);  // ruh is a variable generated by this closure
    });
}

fn main() {
    let foo = Foo { bar: None };
    baz(&mut foo);
}

As expected, the compiler does not pass it as it is unsure about the lifetime of foo. I can declare foo as static but then on_event accepts a Fn closure which does not have mutation capabilities so it fails again. If I use Rc<RefCell<Foo>>, we are back to lifetime errors about foo.

How can I solve it?

Using callbacks is very annoying in Rust, since the callback too must have single-ownership of the things it access. Your options are:

  1. Rc<RefCell<...>>
  2. Message passing channels.

It should be possible to make it work with Rc<RefCell<...>>.

I tried using Rc<RefCell<T>> but the compiler is unable to infer lifetimes and nor providing explicit lifetimes works.

Got it working with use of lazy_static and Mutex but it's not a clean solution and involves use of global state.

You will have to post code, because there is a way to make it work.

There is too much of gtk-rs spaghetti in there across multiple files to put it out here without significant effort.

As noted in the edit of the previous reply, I could get it to work using lazy_static! and Mutex:

lazy_static! {
    static ref FOO: Mutex<Foo> = Mutex::new(foo { bar: None });
}

fn main() {...}

fn baz() { // No longer accepts Foo as arg
    // Additional code that includes declaration of some_local_var
    some_local_var.on_event(|| {  // Fn closure
        FOO.lock().unwrap().bar = Some(ruh);  // ruh is a variable generated by this closure
    });
}

But it's not an elegant solution.

If you post code of your Rc<RefCell<..>>, I can show you how to get it working. What I'm guessing went wrong is that you have to clone the Rc before moving it into the callback.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.