如何在生锈的 GTK 事件中设置结构的值?
How to set the value of a struct inside a GTK event in rust?
如何在 Rust 中设置 GTK 事件中结构的值?
尝试修改下面的 s
结构实例时出现错误。
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
并通过 reference-counted pointer 访问它来解决,这确保对象至少与引用它的闭包一样长。
第二个问题最容易通过内部可变性解决,方法是将 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(&[]);
}
如何在 Rust 中设置 GTK 事件中结构的值?
尝试修改下面的 s
结构实例时出现错误。
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
并通过 reference-counted pointer 访问它来解决,这确保对象至少与引用它的闭包一样长。
第二个问题最容易通过内部可变性解决,方法是将 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(&[]);
}