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.
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.