Search code examples
rustgtk-rs

How to set a variable inside a gtk-rs closure?


I'm building a markdown app, and I want to keep two copies of the text, one a source text, and the other the TextBuffer with all the correct tags and such.

I need to set the contents of this source field inside a closure:

buffer.connect_begin_user_action(clone!(source => move |a| {
  let text = a.get_text(&a.get_start_iter(), &a.get_end_iter(), false).unwrap();
  source = text; // error: cannot assign to captured outer variable in an `Fn` closure

An alternative might be to set some attribute on the TextBuffer, but I don't know if this is possible.


Solution

  • TextBufferExt::connect_begin_user_action() accepts Fn-closures, that is closures which can't change their captured environment. When you need to change something that can't be changed, you can use types with interior mutability, like RefCell.

    If you'll adjust the type of source to RefCell<String> and change assignment inside closure to *source.borrow_mut() = text;, the code will compile, but there's another problem. You assign a value to the cloned source.

    The macro clone! expands into

    {
        let source = source.clone();
        move |a| {
           let text = // ...
           // ...
        }
    }
    

    That is, the closure captures and changes a copy of the variable source, not the original variable. Rc is one of the methods to do what you intended

    use std::cell::RefCell;
    use std::rc::Rc;
    // ...
    let source = Rc::new(RefCell::new("Text".to_string()));
    // ...
    buffer.connect_begin_user_action(clone!(source => move |a| {
        let text = a.get_text(&a.get_start_iter(), &a.get_end_iter(), false).unwrap();
        *source.borrow_mut() = text;
        // ...
    }));
    

    Another method is removing clone! macro and capturing source by reference (you'll need to remove move before closure), but in this case it will not work as connect_begin_user_action() expects a closure with 'static lifetime, that is a closure with no captured references to local variables.