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

如何在Rust中实现支持动态增删订阅者的同步发布订阅系统?

在Rust中实现单线程同步发布订阅系统

你的核心问题在于裸引用无法表达异构生命周期的集合,Rust的类型系统要求Vec中的元素必须是同一种类型(包括生命周期参数),而你需要的是让EventRouter持有不同生命周期的监听器,同时保证这些监听器在被引用期间有效。下面是几种符合单线程同步约束的可行方案:

方案1:用Rc共享所有权(最直观的实现)

单线程场景下,Rc可以安全地共享对象所有权,绕开生命周期的静态检查,通过引用计数管理对象的存活时间。

use std::rc::Rc;

struct EventListener {}
impl EventListener {
    fn on_event(&self, event: &str) {
        println!("{}", event);
    }
}

struct EventRouter {
    listeners: Vec<Rc<EventListener>>,
}

impl EventRouter {
    fn new() -> Self {
        Self { listeners: Vec::new() }
    }

    fn add_listener(&mut self, listener: Rc<EventListener>) {
        self.listeners.push(listener);
    }

    // 支持按索引移除监听器,若需要精准移除可给Listener加唯一ID,改用HashMap存储
    fn remove_listener(&mut self, index: usize) -> Option<Rc<EventListener>> {
        if index < self.listeners.len() {
            Some(self.listeners.remove(index))
        } else {
            None
        }
    }

    fn clear(&mut self) {
        self.listeners.clear();
    }

    fn send(&self, event: &str) {
        for listener in &self.listeners {
            listener.on_event(event);
        }
    }
}

fn main() {
    let mut router = EventRouter::new();

    {
        let listener = Rc::new(EventListener {});
        router.add_listener(listener.clone());

        router.send("Hello, world!");
        router.remove_listener(0);
    }

    router.send("Hello, world!"); // 无输出,监听器已被移除
}

方案2:用 trait 对象封装回调(更灵活)

如果不需要保留EventListener结构体,可以直接将回调逻辑封装为 trait 对象,进一步简化代码:

use std::rc::Rc;

struct EventRouter {
    callbacks: Vec<Rc<dyn Fn(&str)>>,
}

impl EventRouter {
    fn new() -> Self {
        Self { callbacks: Vec::new() }
    }

    fn add_callback(&mut self, callback: Rc<dyn Fn(&str)>) {
        self.callbacks.push(callback);
    }

    fn remove_callback(&mut self, index: usize) -> Option<Rc<dyn Fn(&str)>> {
        if index < self.callbacks.len() {
            Some(self.callbacks.remove(index))
        } else {
            None
        }
    }

    fn clear(&mut self) {
        self.callbacks.clear();
    }

    fn send(&self, event: &str) {
        for callback in &self.callbacks {
            callback(event);
        }
    }
}

fn main() {
    let mut router = EventRouter::new();

    {
        let callback = Rc::new(|event| println!("{}", event));
        router.add_callback(callback.clone());

        router.send("Hello, world!");
        router.remove_callback(0);
    }

    router.send("Hello, world!"); // 无输出
}

方案3:支持可变状态的监听器(单线程)

如果监听器需要修改内部状态,单线程下可以配合RefCell使用:

use std::rc::Rc;
use std::cell::RefCell;

struct EventListener {
    event_count: u32,
}

impl EventListener {
    fn on_event(&mut self, event: &str) {
        self.event_count += 1;
        println!("Received event '{}' (total: {})", event, self.event_count);
    }
}

struct EventRouter {
    listeners: Vec<Rc<RefCell<EventListener>>>,
}

impl EventRouter {
    fn new() -> Self {
        Self { listeners: Vec::new() }
    }

    fn add_listener(&mut self, listener: Rc<RefCell<EventListener>>) {
        self.listeners.push(listener);
    }

    fn send(&self, event: &str) {
        for listener in &self.listeners {
            listener.borrow_mut().on_event(event);
        }
    }
}

fn main() {
    let mut router = EventRouter::new();
    let listener = Rc::new(RefCell::new(EventListener { event_count: 0 }));
    router.add_listener(listener.clone());

    router.send("Test Event");
    router.send("Test Event");
}

为什么原方案不可行?

原代码使用裸引用&EventListener存在两个核心问题:

  1. Rust要求Vec中的所有引用必须具有相同的生命周期,无法存储不同生命周期的监听器;
  2. 裸引用的生命周期必须至少和EventRouter一致,否则会触发悬垂引用检查,即使你在运行时调用了clear,Rust的静态分析也不会认可这种动态操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 01:39:57