Как установить переменную внутри gtk-rs замыкания?

Я создаю приложение уценки и хочу сохранить две копии текста, одну source текст, а другой TextBuffer со всеми правильными тегами и тому подобное.

Мне нужно установить содержимое этого поля источника внутри замыкания:

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

Альтернативой может быть установка какого-либо атрибута на TextBuffer, но я не знаю, возможно ли это.

1 ответ

Решение

TextBufferExt::connect_begin_user_action() принимает Fn- закрытие, то есть закрытие, которое не может изменить их захваченное окружение. Когда вам нужно изменить что-то, что не может быть изменено, вы можете использовать типы с внутренней изменчивостью, например RefCell,

Если вы будете корректировать тип source в RefCell<String> и изменить назначение внутри закрытия на *source.borrow_mut() = text;код скомпилируется, но есть еще одна проблема. Вы назначаете значение клонированному source,

Макрос clone! расширяется в

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

То есть замыкание захватывает и изменяет копию переменной source, а не исходная переменная. Rc это один из способов сделать то, что вы хотели

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;
    // ...
}));

Другой метод удаления clone! макрос и захват source по ссылке (вам нужно удалить move до закрытия), но в этом случае он не будет работать как connect_begin_user_action() ожидает закрытия с 'static время жизни, это замыкание без захваченных ссылок на локальные переменные.

Другие вопросы по тегам