【问题标题】:Global application state with FLTK libraryFLTK 库的全局应用程序状态
【发布时间】:2023-01-28 05:55:50
【问题描述】:

我正在使用 fltk 库编写应用程序。 应用程序的体系结构涉及一个全局状态,它存储现在要显示哪个页面(查看器)并存储查看器数据。 有一些按钮可以发送消息来更新和更改全局状态,指示现在显示哪个查看器。

#[derive(Clone, Copy)]
enum Message {
    Update
}

#[derive(Clone, Copy)]
struct GlobalState {
    viewer: Viewer,
}

impl GlobalState {
    fn set_viewer(&mut self, v: Viewer) {
        self.viewer = v;
    }
}

#[derive(Clone, Copy)]
enum Viewer {
    Page1,
    Page2
}

fn main() {
    let mut gs = GlobalState {viewer: Viewer::Page1};

    let app = app::App::default().with_scheme(app::Scheme::Gtk);
    let (s, r) = app::channel::<Message>();
    let mut wind = Window::default().with_size(800, 600);

    left_side(&mut gs);

    let mut col = Column::new(155,70,800 - 150,600 - 65,None);
    s.send(Message::Update);
    col.end();
    wind.end();
    wind.show();

    while app.wait() {
        if let Some(msg) = r.recv() {
            match msg {
                Message::Update => {
                    match gs.viewer {
                        Viewer::Page1 => {
                            col.clear();
                            let view = view_ohm();
                            col.add(&view);
                        },
                        Viewer::Page2 => {
                            col.clear();
                            let view = view_ohm();
                            col.add(&view);
                        },
                        _ => ()
                    }
                }
                _ => (),
            }
        }
    }
}

fn left_side(gs: &mut GlobalState) {
    let btn_width = 130;
    let btn_height = 30;

    let (s, r) = app::channel::<Message>();

    let mut grp = Group::default().with_size(65, 600);
    let mut col = Pack::default()
        .with_size(btn_width, 600)
        .center_of_parent()
        .with_type(PackType::Vertical);
    col.set_spacing(2);

    let mut btn = Button::new(0, 0, btn_width, btn_height, "Page 1");
    btn.emit(s, Message::Update);
    btn.set_callback(|_| {
        gs.set_viewer(Viewer::Page1)
    });

    let mut btn = Button::new(0, 0, btn_width, btn_height, "Page 2");
    btn.emit(s, Message::Update);
    btn.set_callback(|_| {
        gs.set_viewer(Viewer::Page2)
    });

    col.end();
    grp.end();
}

问题:

  1. 代码没有编译错误:
        error[E0521]: borrowed data escapes outside of function
          --> src/main.rs:89:5
           |
        74 |   fn left_side(gs: &mut GlobalState) {
           |                --  - let's call the lifetime of this reference `'1`
           |                |
           |                `gs` is a reference that is only valid in the function body
        ...
        89 | /     btn.set_callback(|_| {
        90 | |         gs.set_viewer(Viewer::Page1)
        91 | |     });
           | |      ^
           | |      |
           | |______`gs` escapes the function body here
           |        argument requires that `'1` must outlive `'static`
        
        error[E0524]: two closures require unique access to `*gs` at the same time
          --> src/main.rs:95:22
           |
        89 |       btn.set_callback(|_| {
           |       -                --- first closure is constructed here
           |  _____|
           | |
        90 | |         gs.set_viewer(Viewer::Page1)
           | |         -- first borrow occurs due to use of `*gs` in closure
        91 | |     });
           | |______- argument requires that `*gs` is borrowed for `'static`
        ...
        95 |       btn.set_callback(|_| {
           |                        ^^^ second closure is constructed here
        96 |           gs.set_viewer(Viewer::Page2)
           |           -- second borrow occurs due to use of `*gs` in closure
    
    1. 我的应用程序架构有效还是有更好的架构?该应用程序有多个页面(一页一个查看器),每个查看器都有自己的全局状态和存储在其中并处理这些数据的数据。

    2. 在全局状态中存储查看器数据的最佳方式是什么?

【问题讨论】:

  • 您在多个闭包中使用 gs: &amp;mut GlobalState。在闭包中使用引用本质上是将该引用放在闭包结构上。但是,编译器不允许您同时拥有多个活动的可变(唯一)引用。您必须使用 RefCellMutex 之类的东西来通过不可变(共享)引用允许内部可变性。
  • 我尝试使用 RefCell 但代码不再起作用:``` #[derive(Clone)] struct GlobalState { viewer: RefCell<Viewer>, } impl GlobalState { fn set_viewer(&self, v: Viewer) { *self .viewer.borrow_mut() = v; } } fn main() { let gs = GlobalState {viewer: RefCell::new(Viewer::Page1)}; .... 左侧(gs); ... } fn left_side(gs: GlobalState) { .... btn.set_callback(|_| { gs.set_viewer(Viewer::Page1) }); ....}```
  • 将代码和产生的错误编辑到您的问题中

标签: user-interface rust fltk


【解决方案1】:

此代码将您的 GlobalState 包装在 Rc&lt;RefCell&lt;GlobalState&gt;&gt; 中:

#[derive(Clone, Copy)]
enum Message {
    Update
}

#[derive(Clone, Copy)]
struct GlobalState {
    viewer: Viewer,
}

impl GlobalState {
    fn set_viewer(&mut self, v: Viewer) {
        self.viewer = v;
    }
}

#[derive(Clone, Copy)]
enum Viewer {
    Page1,
    Page2
}

fn main() {
    let mut gs = Rc::new(RefCell::new(GlobalState {viewer: Viewer::Page1}));

    let app = app::App::default().with_scheme(app::Scheme::Gtk);
    let (s, r) = app::channel::<Message>();
    let mut wind = Window::default().with_size(800, 600);

    left_side(gs.clone());

    let mut col = Column::new(155,70,800 - 150,600 - 65,None);
    s.send(Message::Update);
    col.end();
    wind.end();
    wind.show();

    while app.wait() {
        if let Some(msg) = r.recv() {
            match msg {
                Message::Update => {
                    let gs = gs.borrow();
                    match gs.viewer {
                        Viewer::Page1 => {
                            col.clear();
                            let view = view_ohm();
                            col.add(&view);
                        },
                        Viewer::Page2 => {
                            col.clear();
                            let view = view_ohm();
                            col.add(&view);
                        },
                        _ => ()
                    }
                }
                _ => (),
            }
        }
    }
}

fn left_side(gs: Rc<RefCell<GlobalState>>) {
    let btn_width = 130;
    let btn_height = 30;

    let (s, r) = app::channel::<Message>();

    let mut grp = Group::default().with_size(65, 600);
    let mut col = Pack::default()
        .with_size(btn_width, 600)
        .center_of_parent()
        .with_type(PackType::Vertical);
    col.set_spacing(2);

    let mut btn = Button::new(0, 0, btn_width, btn_height, "Page 1");
    btn.emit(s, Message::Update);
    btn.set_callback({
        let gs = gs.clone();
        move |_| {
        gs.borrow_mut().set_viewer(Viewer::Page1)
    }});

    let mut btn = Button::new(0, 0, btn_width, btn_height, "Page 2");
    btn.emit(s, Message::Update);
    btn.set_callback(move |_| {
        gs.borrow_mut().set_viewer(Viewer::Page2)
    });

    col.end();
    grp.end();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-14
    • 2017-03-28
    • 1970-01-01
    • 2017-10-19
    • 1970-01-01
    • 2019-11-22
    • 2013-06-05
    相关资源
    最近更新 更多