0

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
dessalines
  • 6,352
  • 5
  • 42
  • 59
  • 1
    Why do you think that usage of this library will change the semantics and rules of the rest of the language? Said another way, why do you think that it's important that gtk-rs is in use? Could this be closed as a duplicate of a hypothetical question that is "How to set a variable inside a Rust closure" ? – Shepmaster Aug 15 '17 at 22:08
  • I'm not sure what to rename the question to. – dessalines Aug 15 '17 at 22:14

1 Answers1

3

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
red75prime
  • 3,733
  • 1
  • 16
  • 22