首页 > 解决方案 > Rust 异步方法回调/关闭

问题描述

我有一个情况,有一个服务管理器(结构 B)持有一个数字服务(结构 A),需要调用服务管理器中的一个方法(例如 self.test with self in B),所有工作都深深嵌套在 async tokio代码。虽然我能够将服务管理器的克隆“附加”到每个服务以便能够调用其方法,但我希望只允许访问服务管理器中的特定 async(!) 方法,即我只想例如,将服务管理器的一种方法附加到服务。(对于那些对真实系统感兴趣的人,一些服务调用其他服务中的方法并通过服务管理器中的调用来获取它们,我知道有频道、发布/订阅等内容,但我对这个特定的解决方案感兴趣设置,因为我经常遇到它... ) 不幸的是,我无法找到正确的方法来设置这样的回调。下面是整个设置的一个非常简化的版本:

#![feature(async_closure)]

use std::sync::Arc;

type AsyncClosure = ???;

struct A {
    value: String,
    callback_to_fn_in_B: Option<AsyncClosure>,
}

impl A {
    fn set_callback_to_method_in_B(&mut self, f: Option<AsyncClosure>) {
        self.callback_to_fn_in_B = f;
    }
}

struct B {
    b: String,
    a: Arc<A>,
}

impl B {
    async fn test(&self, arg0: &str) -> String {
        // to simulate some async work:
        tokio::time::sleep(std::time::Duration::from_secs(1)).await;
        format!("b + arg0 = {}{}", self.b, arg0)
    }

    fn attach_self_callback_to_A(&self) {
        let callback = async move |arg: &str| {
            self.test(arg).await
        };
        self.a.set_callback_to_method_in_B(Some(callback));
    }
}
#[tokio::main]
async fn main() {
    tokio::spawn(async move {
        let a = Arc::new(A { value: "value".to_owned(), callback_to_fn_in_B: None });
        let b = B { b: "hello".to_owned(), a: a.clone()  };
        b.attach_self_callback_to_A();
        match a.callback_to_fn_in_B.as_ref() {
            Some(f) => println!("{:?}", f(" world")),
            None => {},
        }
        
    });
}

我把 tokio 等留在了那里,以表明整个系统应该跨线程工作,即某些部分可能需要 + 发送 + 同步。如何定义 AsyncClosure 类型?是否可以避免关闭(我会用它来捕获主体结构 B 的自我)?任何帮助是极大的赞赏!

基于下面的第一个答案,我转到以下版本:

#![feature(async_closure)]
#![allow(unused_imports)]

use std::sync::Arc;
use std::error::Error;
use futures::future::Future;
use std::pin::Pin;

type AsyncClosure = Box<dyn for<'a> FnMut(&'a str) -> Pin<Box<dyn Future<Output = String> + 'a + Send + Sync>> + Send + Sync>;
struct A
{
    value: String,
    callback_to_fn_in_B: Option<AsyncClosure>,
}

impl A
{    
    fn set_callback_to_method_in_B(&mut self, f: Option<AsyncClosure>) {
        self.callback_to_fn_in_B = f;
    }
}

struct B
{
    b: String,
    a: Arc<A>,
}

impl B
{
    async fn test(&self, arg0: &str) -> String {
        // to simulate some async work:
        tokio::time::sleep(std::time::Duration::from_secs(1)).await;
        format!("b + arg0 = {}{}", self.b, arg0)
    }

    async fn attach_self_callback_to_A(&self) {
        let this = self.clone();
        let callback: AsyncClosure = Box::new(|arg| { Box::pin(async move { this.test(arg).await })});
        self.a.set_callback_to_method_in_B(Some(callback));
    }
}

#[tokio::main]
async fn main() {
    tokio::spawn(async move {
        let a = Arc::new(A { value: "value".to_owned(), callback_to_fn_in_B: None });
        let b = B { b: "hello".to_owned(), a: a.clone()  };
        b.attach_self_callback_to_A();
        match a.callback_to_fn_in_B.as_ref() {
            Some(f) => {
               println!("{:?}", f("test").await)
            },
            None => {},
        }
        
    });
}

但是,现在编译器抱怨说,由于 fn attach_self_callback_to A 中 &self 的要求相互冲突,它无法推断出适当的生命周期。错误消息很长,而且大部分都是重复的,没有给我任何真正的帮助。有人知道如何解决这个问题吗?

标签: asynchronousmethodsrustcallbackself

解决方案


推荐阅读