You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在connect_activate外创建glib::MainContext::channel并传入处理?

问题:在GTK应用初始化前创建glib通道并传递Receiver到激活回调

我是Rust和GTK的新手,希望在初始化gtk::Application之前创建glib::MainContext::channel对,我认为它的作用和std::sync::mpsc完全一致。虽然我能创建并保存rx/tx通道对,但不确定如何将Receiver传入gtk::Application::connect_activate()信号处理器中以调用.attach()。

我修改的示例代码如下:

struct MyData {
    ready_tx: glib::Sender<i32>,
    //ready_rx: glib::Receiver<i32>,
}

fn setup() -> MyData {
    let (ready_tx, ready_rx) = glib::MainContext::channel(glib::Priority::default());
    MyData {
        ready_tx,
        //ready_rx,
    }
}

fn main() {
    let data = setup();

    //
    // Setup other threads by cloning data.sender
    //

    let application = gtk::Application::new(
        Some("com.github.gtk-rs.examples.cairo_threads"),
        Default::default(),
    );

    application.connect_activate(move |app| {
        build_ui(&app, &data)
    });

    application.run();
}

fn build_ui(application: &gtk::Application, data: &MyData) {
    ...
    data.ready_rx.attach( {
        ...
    });
}

上述代码(忽略未实现的build_ui)可编译运行,但存在明显问题:ready_rx并未被包含进去。若添加ready_rx,则会在build_ui()中出现错误:move occurs because data.ready_rx has type glib::Receiver, which does not implement the Copy trait。

我希望将Receiver<i32>的所有权从setup()函数传递到main,最终被build_ui()函数消费,但不清楚实现方式,也不理解为何需要Copy trait,且我无法克隆Receiver。我需要先创建一些额外线程,这些线程在初始化GTK GUI前就需要Sender的引用,因此想这样实现,但未找到在build_ui()外创建glib::MainContext::channel对的示例,是否有其他方案?


解决方案

感谢@chayim-friedman的解答,修改后的代码如下:

use std::cell::Cell;

struct MyData {
    ready_tx: glib::Sender<i32>,
    ready_rx: Cell<Option<glib::Receiver<i32>>>,
}

fn setup() -> MyData {
    let (ready_tx, ready_rx) = glib::MainContext::channel(glib::Priority::default());
    MyData {
        ready_tx,
        ready_rx: Cell::new(Some(ready_rx)),
    }
}

fn main() {
    let data = setup();

    //
    // Setup other threads by cloning data.sender
    //

    let application = gtk::Application::new(
        Some("com.github.gtk-rs.examples.cairo_threads"),
        Default::default(),
    );

    application.connect_activate(move |app| {
        build_ui(&app, &data)
    });

    application.run();
}

fn build_ui(application: &gtk::Application, data: &MyData) {
    ...
    data.ready_rx.take().unwrap().attach( {
        ...
    });
}

思路说明

用Cell<Option<glib::Receiver<i32>>>包装Receiver:

  • Cell允许在持有不可变引用的情况下修改内部值,适配build_ui中对data的不可变引用场景
  • Option的take()方法会取出内部的Receiver并留下None,一次性转移所有权,刚好满足attach()需要消费Receiver所有权的需求,避免了移动语义冲突

内容的提问来源于stack exchange,提问作者awm129

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 19:57:39