如何在生锈的 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 包装成 RefCellRefCell 持有一个值并允许持有者通过对 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(&[]);
}