如何在rust的GTK事件中设置结构的值?尝试修改s
下面的struct实例时出现错误。
use gtk::prelude::*;
use gio::prelude::*;
use gtk::{Application, ApplicationWindow, Button};
struct SomeStruct {
val: bool,
}
fn main() {
let mut s = SomeStruct {
val: false,
};
application.connect_activate(|app| {
let window = ApplicationWindow::new(app);
window.set_title("test");
window.set_default_size(350,70);
let button = Button::with_label("Test");
button.connect_clicked(|_|{
s.val = true; // error here
});
window.add(&button);
window.show_all();
});
application.run(&[]);
}
错误讯息:
error[E0597]: `s` does not live long enough
error[E0596]: cannot borrow `s` as mutable, as it is a captured variable in a `Fn` closure
你的代码有两个问题:
s
使用GTK应用程序,但Rust并不知道这一点,这就是为什么它抱怨s
寿命不足的原因。ButtonExt::connect_clicked()
接受Fn
,因此在没有额外预防措施的情况下不允许对数据进行突变。可以通过s
在堆上分配并通过引用计数的指针对其进行访问来解决第一个问题,这可确保对象的生存至少与引用它的闭包一样长。
第二个问题最简单的解决方法是通过包装SomeStruct
成,通过内部可变性解决RefCell
。RefCell
持有一个值,并允许持有人通过对的共享引用对其进行突变RefCell
。当请求mut
对内部值的引用时,RefCell
将在运行时检查是否还没有其他对该值的引用处于活动状态。(如果你的闭包要访问该值,然后在保持该值的同时调用另一个执行相同操作的闭包,则可能会发生这种情况。)
两者结合起来将导致这样的代码(未经测试):
use std::rc::Rc;
use std::cell::RefCell;
fn main() {
let s = Rc::new(RefCell::new(SomeStruct { val: false }));
application.connect_activate(|app| {
let window = ApplicationWindow::new(app);
window.set_title("test");
window.set_default_size(350, 70);
let button = Button::with_label("Test");
// clone the handle to s and move it into the closure
let s2 = Rc::clone(&s);
button.connect_clicked(move |_| {
s2.borrow_mut().val = true;
});
window.add(&button);
window.show_all();
});
application.run(&[]);
}