【问题标题】:How could I store closures and use them with Actix actors?我如何存储闭包并将它们与 Actix 演员一起使用?
【发布时间】:2018-10-13 06:52:22
【问题描述】:

我正在尝试使用 Actix 通过 WebSocket 传递捕获事件,并使用 https://github.com/foochi/how-store-closures-with-actix 之类的东西处理它们。这个想法是提供一个库,可用于存储闭包(事件),并在收到 WebSockets 文本消息时运行它们。

use actix::*;
use actix_web::ws::{Client, Message, ProtocolError};
use futures::Future;

struct MyActor {
    handler: Box<Fn(String) + 'static>,
}

impl Actor for MyActor {
    type Context = Context<Self>;
}

impl StreamHandler<Message, ProtocolError> for MyActor {
    fn handle(&mut self, msg: Message, _ctx: &mut Context<Self>) {
        match msg {
            Message::Text(text) => {
                (self.handler)(text)
            },
            _ => panic!(),
        }
    }
}

pub struct Event {
    handler: Box<Fn(String) + 'static>,
}

pub struct EventManager {
    events: Vec<Event>,
}

impl EventManager {

    pub fn new() -> Self {
        Self { events: vec![] }
    }

    pub fn capture<F>(&mut self, function: F)
    where
        F: for<'h> Fn(String) + 'static
    {
        let event = Event { handler: Box::new(function), };
        self.events.push(event);
    }

    pub fn run(&self) {
        let runner = System::new("example");
        let event = &self.events[0];

        Arbiter::spawn(
            Client::new("example")
                .connect()
                .map(|(reader, _writer)| {
                    MyActor::create(|ctx| {
                        MyActor::add_stream(reader, ctx);
                        MyActor { handler: event.handler }
                    });
                })
                .map_err(|err| {})
        );

        runner.run();
    }
}

我的问题是我有这个错误:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/events.rs:48:22
   |
48 |         let event = &self.events[0];
   |                      ^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 46:5...
  --> src/events.rs:46:5
   |
46 | /     pub fn run(&self) {
47 | |         let runner = System::new("example");
48 | |         let event = &self.events[0];
49 | |
...  |
62 | |         runner.run();
63 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/events.rs:48:22
   |
48 |         let event = &self.events[0];
   |                      ^^^^^^^^^^^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/events.rs:54:37: 57:22 reader:actix_web::ws::ClientReader, event:&&events::Event]` will meet its required lifetime bounds
  --> src/events.rs:54:21
   |
54 |                     MyActor::create(|ctx| {
   |                     ^^^^^^^^^^^^^^^

我认为我部分理解了根本原因:我试图将引用(事件)传递给 StreamHandler,但生命周期不匹配。

我该如何解决?

【问题讨论】:

    标签: rust lifetime rust-actix


    【解决方案1】:

    免责声明:我无法评论这是否是 Actix 的良好设计模式,因为我刚刚开始了解该框架。

    正如您已经发现的那样,问题与生命周期要求有关。

    Actor::create 方法的闭包参数需要 'static 生命周期:

    fn create<F>(f: F) -> Addr<Self> 
    where
        Self: Actor<Context = Context<Self>>,
        F: FnOnce(&mut Context<Self>) -> Self + 'static, 
    

    &amp;self.events[0] 不满足'static 的生命周期要求。

    一种解决方案是将EventManager 对象的所有权转移到MyActor

    use actix::*;
    use actix_web::ws::{Client, Message, ProtocolError};
    use futures::Future;
    
    struct MyActor {
        evm: EventManager,
    }
    
    impl Actor for MyActor {
        type Context = Context<Self>;
    }
    
    impl StreamHandler<Message, ProtocolError> for MyActor {
        fn handle(&mut self, msg: Message, _ctx: &mut Context<Self>) {
            match msg {
                Message::Text(text) => {
                    // just for sake of demo: execute all event handlers
                    for idx in 0..self.evm.events.len() {
                        (self.evm.events[idx].handler)(text.clone())
                    }
                }
                _ => panic!(),
            }
        }
    }
    
    pub struct Event {
        handler: Box<Fn(String) + 'static>,
    }
    
    pub struct EventManager {
        events: Vec<Event>,
    }
    
    impl EventManager {
        pub fn new() -> Self {
            Self { events: vec![] }
        }
    
        pub fn capture<F>(&mut self, function: F)
        where
            F: Fn(String) + 'static,
        {
            let event = Event {
                handler: Box::new(function),
            };
            self.events.push(event);
        }
    
        pub fn run(self) {
            let runner = System::new("example");
    
            Arbiter::spawn(
                Client::new("http://127.0.0.1:8080/ws/")
                    .connect()
                    .map(|(reader, _writer)| {
                        MyActor::create(|ctx| {
                            MyActor::add_stream(reader, ctx);
    
                            // move event manager inside the actor
                            MyActor { evm: self }
                        });
                    }).map_err(|err| println!("FATAL: {}", err)),
            );
    
            runner.run();
        }
    }
    
    pub fn ready() {
        let mut client = EventManager::new();
    
        client.capture(|data| println!("processing the data: {:?}", data));
        client.capture(|data| println!("processing AGAIN the data: {:?}", data));
        client.run();
    
        // here run client is not more available: it was moved inside the actor
    }
    
    fn main() {
        ready();
    }
    

    【讨论】:

    • 谢谢@attdona!您的回答不仅解决了我的问题,而且现在我已经学会了一种不同的方式来推理生命周期和所有权。
    猜你喜欢
    • 2014-01-20
    • 1970-01-01
    • 2022-11-07
    • 2020-11-08
    • 2018-04-01
    • 2014-08-29
    • 2014-08-25
    • 2019-12-13
    • 2020-10-08
    相关资源
    最近更新 更多