Warm tip: This article is reproduced from serverfault.com, please click

其他-如何在Rust的GTK事件中设置结构的值?

(其他 - How to set the value of a struct inside a GTK event in rust?)

发布于 2020-11-28 12:04:56

如何在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
Questioner
Andrzej C
Viewed
0
user4815162342 2020-11-29 07:11:15

你的代码有两个问题:

  • 尽管没有s使用GTK应用程序,但Rust并不知道这一点,这就是为什么它抱怨s寿命不足的原因。
  • ButtonExt::connect_clicked()接受Fn,因此在没有额外预防措施的情况下不允许对数据进行突变。

可以通过s在堆上分配并通过引用计数的指针对其进行访问来解决第一个问题,这可确保对象的生存至少与引用它的闭包一样长。

第二个问题最简单的解决方法是通过包装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(&[]);
}