首页 文章

如何将变量移出闭包?

提问于
浏览
5

我有一个简单的GTK应用程序,我需要选择一个文件夹并将其路径传递给闭包之外的变量 .

let mut path = "".to_owned();

button_open.connect_clicked(move |_| {
    let file_chooser = gtk::FileChooserDialog::new(
        "Open File", None, gtk::FileChooserAction::SelectFolder,
        [("Open", gtk::ResponseType::Ok), ("Cancel", gtk::ResponseType::Cancel)]);
    if file_chooser.run() == gtk::ResponseType::Ok as i32 {
        let filename = file_chooser.get_current_folder().unwrap();
    }

    file_chooser.destroy();
});

如何将 filename 分配给 path ?如果我只是写

path = filename;

我收到此错误:

src\main.rs:46:13: 46:28 error: cannot assign to captured outer variable in an `Fn` closure
src\main.rs:46             path = filename;

1 回答

  • 8

    出于几个原因你不能这样做 . Hereconnect_clicked() 方法的定义:

    fn connect_clicked<F: Fn(Button) + 'static>(&self, f: F) -> u64
    

    此方法接受的闭包是 Fn ,并且由 'static 限定 . 这意味着,首先,它不能修改其环境(即 FnMut ),它也无法通过引用捕获任何内容(大致是 'static 的意思) . 因此,闭包无法像您想要的那样修改 path 变量 .

    鉴于gtk-rs enforces,GTK只能在主线程中使用,而且它的小部件不是 Send 能够,处理程序无法从另一个线程访问变量,所以我不确定为什么这些闭包有 'static 绑定,我也完全没有理由他们不是 FnMut . 这似乎是一个实现缺陷 .

    无论如何,您可以使用 Rc<RefCell<..>> 创建可变数据:

    let path: Rc<RefCell<Option<String>>> = Rc::new(RefCell::new(None));
    let captured_path = path.clone();  // clone the Arc to use in closure
    ...
    // inside the closure
    *captured_path.borrow_mut() = Some(filename);
    

    也可以使用 Arc<Mutex<..>> ,但我不认为这是必要的,因为gtk-rs可以防止从主线程以外的任何线程使用GTK .

相关问题