I have a simple GTK app and I need to select a folder and pass it's path to a variable outside of the closure.
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();
});
How do I assign filename
to path
? If I just write
path = filename;
I get this error:
src\main.rs:46:13: 46:28 error: cannot assign to captured outer variable in an `Fn` closure
src\main.rs:46 path = filename;
A closure is the combination of a function and the lexical environment within which that function was declared. ... Closures are useful because they let you associate some data (the lexical environment) with a function that operates on that data.
Each closure references a different version of the privateCounter variable through its own closure. Each time one of the counters is called, its lexical environment changes by changing the value of this variable. Changes to the variable value in one closure don't affect the value in the other closure.
Closures A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.
Then if the callback closes over the variables in the main thread, there may be problems. Most dire ones are mitigated by 'staticbound, but data races are still possible without synchronization which in gtk-rsis not enforced (no Sendbound on closures). – Vladimir Matveev Jan 7 '16 at 14:35 1 Thanks for your reply. If you don't mind, one question.
You can't do this for several reasons. Here is the definition of connect_clicked()
method:
fn connect_clicked<F: Fn(Button) + 'static>(&self, f: F) -> u64
The closure which this method accepts is Fn
and is bounded by 'static
. This means, first, that it can't modify its environment (that would be FnMut
) and it also can't capture anything by reference (roughly what 'static
means). Therefore, there is no way for the closure to modify the path
variable like you want.
Given that gtk-rs enforces that GTK can only be used from the main thread, and its widgets are not Send
able, there is no way for the handler to access variables from another thread, so I'm not sure why these closures have 'static
bound, and I also see absolutely no reason why they are not FnMut
. This seems to be an implementation defect.
Anyway, you can use Rc<RefCell<..>>
to create a mutable piece of data:
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);
It is also possible to use Arc<Mutex<..>>
, but I don't think it is necessary because gtk-rs protects against using GTK from any thread except the main one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With