在Rust中是否有像NodeJS的EventEmitter这样的功能?

时间:2014-10-08 08:17:48

标签: node.js rust

我正在寻找一个中心“对象”,多个任务可以“订阅”异步更新消息。

2 个答案:

答案 0 :(得分:3)

据我了解,EventEmitter只是事件监听器支持的通用接口; "实施的对象"此接口提供了几种事件,客户端代码可以在其上放置侦听器回调。然后,当对象自行决定发出相应的事件时,将调用这些回调。由于JS是动态类型语言,因此这种界面非常自然地出现并且可以通过很多东西来实现。

首先,无论是在NodeJS还是在Rust中,你都可以"订阅" tasks / threads:你在一些对象上放置一个监听器回调,然后这个回调将从某个线程调用,甚至可能是当前的调用,但通常是订阅一个对象的线程和运行这个回调的线程是不同的。在NodeJS中有一个全局事件循环,它调用函数和外部事件监听器,而这些监听器又可以调用其他事件监听器,因此你不知道哪个线程将执行监听器。不是你应该关心 - 事件循环抽象隐藏了你的显式线程。

然而,Rust是一种适当的多线程语言。它不会在全局事件循环上运行(虽然通过libgreen仍然可以 - 在类似于Node中的事件循环中运行Rust程序;它将用于任务管理和I / O处理,但它将在不久的将来与libstd分开。默认Rust运行时libnative公开了用于创建本机抢占式调度线程和本机I / O的工具。这意味着哪个线程最终执行回调并不重要,您应该记住所有回调都将在拥有该对象的线程中执行,除非它创建专门用于事件处理的单独线程。

侦听器的另一个问题是Rust是静态类型语言,并且在静态类型语言中编写泛型事件侦听器接口比在动态类型语言中更难,因为您需要编写足够多态的界面。您还希望利用强类型系统,并使您的界面尽可能安全。这不是一项微不足道的任务。当然,可以在任何地方使用Box<Any>,但这样的API使用起来不会很愉快。

所以,目前还没有通用的事件监听器接口。也没有活动总线库。但是,你总是可以自己写点东西。如果它不是非常通用的,那么编写它应该非常困难。

答案 1 :(得分:1)

我尝试了this的方式,它对我来说很好用,就像这样简单:

  • 定义对象struct
  • 定义您的Listeners
  • 定义标准函数,我们称它们为Extensions
  • 通过执行EmitterExtensions选项添加到Self::Fn<Listener>

下面是我在playground中使用的相同代码,我只是在锈蚀forum中解决了它:

// 1. Define your object
//#[derive(Debug)]
pub struct Counter {
 count: i32,
}

// 2. (Optional), if do not want to use `#[derive(Debug)]` 
//    you can define your own debug/release format
impl std::fmt::Debug for Counter {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Counter `count` is: {}", self.count)
    }
}

// 3. Define your Listeners trait 
trait EventListener {
     fn on_squared() {
        println!("Counter squared")
     }
     fn on_increased(amount: i32) {
        println!("Counter increased by {}", amount)
     }
     fn on_decreased(self, amount: i32);
}

// 4. Implement your Listeners trait to your object
impl EventListener for Counter {
    fn on_decreased(self, amount: i32) {
        println!("Counter reduced from {} to {}", &self.count, &self.count - amount)
    }
}

// 5. (Recommended), Define your standard functions/Extensions/Emitters
//    trait signatures
trait EventEmitter {
    fn square(&mut self);
    fn increase(&mut self, amount: i32);
    fn decrease(&mut self, amount: i32);
    fn change_by(&mut self, amount: i32);
}

// 6. Implement your standard functions/Extensions/Emitters trait to your object
impl EventEmitter for Counter {
    fn square(&mut self) { 
        self.count = self.count.pow(2);
        Self::on_squared();      // This is Event Emitter, calling the Listner
    }
    fn increase(&mut self, amount: i32) { 
        self.count = self.count + amount; 
        Self::on_increased(amount);   // This is Event Emitter, calling the Listner
    }
    fn decrease(&mut self, amount: i32) {
        let initial_value = self.count;
        self.count = self.count - amount;
        Self::on_decreased(Self {count: initial_value}, amount);  // This is Event Emitter, calling the Listner
    }
    fn change_by(&mut self, amount: i32) {
        let initial_value = self.count;
        self.count = self.count + amount;
        match amount {
            x if x > 0 => Self::on_increased(amount),   // This is Event Emitter, calling the Listner
            x if x < 0 => Self::on_decreased(Self {count: initial_value},  // This is Event Emitter, calling the Listneramount.abs()),
            _   => println!("No changes")
        }
    }
}

// 7. Build your main function
fn main() {
    let mut x = Counter { count: 5 };
    println!("Counter started at: {:#?}", x.count);
    x.square();   // Call the extension, which will automatically trigger the listner
    println!("{:?}", x);
    x.increase(3);
    println!("{:?}", x);
    x.decrease(2);
    println!("{:?}", x);
    x.change_by(-1);
    println!("{:?}", x);
}

并获得以下输出:

Counter started at: 5
Counter squared
Counter `count` is: 25
Counter increased by 3
Counter `count` is: 28
Counter reduced from 28 to 26
Counter `count` is: 26
Counter reduced from 26 to 25
Counter `count` is: 25