rust 当把函数参数移到HashMap中时,如何克服参数类型的改变?

sy5wg1nm  于 2022-12-19  发布在  其他
关注(0)|答案(1)|浏览(103)

下面的代码描述了一个容器,用于使用HashMap准备好的异步调用:

use std::{
    collections::HashMap,
    any::Any,
    marker::Send
};
use futures::future::{Future, BoxFuture};

// ===================================

pub type AnyType = Box<dyn Any + Send>;

// ===================================

trait AsyncFn {
    fn call(&self, arg: AnyType) -> BoxFuture<'static, ()>;
}

impl<T, F> AsyncFn for T
where
    T: Fn(AnyType) -> F,
    F: Future<Output = ()> + 'static + Send,
{
    fn call(&self, arg: AnyType) -> BoxFuture<'static, ()> {
        Box::pin(self(arg))
    }
}

async fn async_test(data: AnyType) -> () {
    let d: Box<String> = data.downcast().unwrap();
    println!("String data = {d:?}");
}

#[async_std::main]
async fn main() {
    let mut callables: HashMap<String, Box<dyn AsyncFn>> = HashMap::new();
    callables.insert(
        "test_func".to_string(),
        Box::new(async_test)
    );

    let awaitable = callables.get("test_func").unwrap();
    awaitable.call(Box::new("test string argument1".to_string())).await;
}

我所面临的任务是为将来的调用做准备,不仅要准备一个异步函数,还要准备一个额外的相关参数,我试着这样做:

use std::{any::Any, collections::HashMap};
use futures::future::{Future, BoxFuture};

pub type AnyType = Box<dyn Any + Send + Sync>;
pub type AnyBindType = Option<AnyType>;

// ===================================

trait AsyncBindFn {
    fn call(&self, arg: AnyBindType) -> BoxFuture<'static, ()>;
}

impl<T, F> AsyncBindFn for T
where
    T: Fn(AnyBindType) -> F,
    F: Future<Output = ()> + 'static + Send + Sync,
{
    fn call(&self, arg: AnyBindType) -> BoxFuture<'static, ()> {
        Box::pin(self(arg))
    }
}

async fn async_test2(data: AnyBindType) -> () {
    if let Some(ref d) = data {
        let d = d.downcast_ref::<String>();
        println!("String data = {d:?}");
    }
}

#[tokio::main]
async fn main() {

    let mut bind_callables: HashMap<String, (Box<dyn AsyncBindFn>, AnyBindType)> = HashMap::new();
    bind_callables.insert(
        "bind_test_func".to_string(),
        (
            Box::new(async_test2),
            Some(Box::new("test bind string argument1".to_string())),
        ),
    );

    let bind_awaitable_data = bind_callables.get("bind_test_func").unwrap();
    let (bind_awaitable, bind_arg) = bind_awaitable_data;

    // if let Some(ref d) = bind_arg {
    //     let d = d.downcast_ref::<String>();
    //     println!("String data = {d:?}");
    // }

    bind_awaitable.call(bind_arg).await; // ! ERROR
    //                  ^^^^^^^^ - mismatched type
}

在数据被传输到HashMap之后,获取原始数据的唯一方法是在其上执行remove(),但我需要能够重用它。
在最后一个例子中,if let的最后一个注解块成功地打印了这个数据,但是由于它是一个引用,我不能发送它在相应的函数中做同样的事情,因为它是一个类型不匹配。
因此,签名的描述应该相应地改变,以便函数引用一个可选参数,但是当我接收到它时,我将引用一个可选数据的引用,等等......
如何克服这种情况?

6ojccjat

6ojccjat1#

impl Future应在返回值定义中显式使用:

use std::{any::Any, collections::HashMap};
use futures::future::{Future, BoxFuture};

pub type AnyBindType = Option<Box<dyn Any + Send + Sync>>;

// ===================================

trait AsyncBindFn {
    fn call(&self, arg: &AnyBindType) -> BoxFuture<'static, ()>;
}

impl<T, F> AsyncBindFn for T
where
    T: Fn(&AnyBindType) -> F,
    F: Future<Output = ()> + 'static + Send + Sync,
{
    fn call(&self, arg: &AnyBindType) -> BoxFuture<'static, ()> {
        Box::pin(self(arg))
    }
}

fn string_test(data: &AnyBindType) -> impl Future<Output = ()> {
    if let Some(d) = data {
        let data = d.downcast_ref::<String>().unwrap().clone();
        println!("String data = {data:?}");

    };
    return async move {};
}

#[tokio::main]
async fn main() {

    let mut bind_callables: HashMap<String, (Box<dyn AsyncBindFn>, AnyBindType)> = HashMap::new();
    bind_callables.insert(
        "bind_test_func".to_string(),
        (
            Box::new(string_test),
            Some(Box::new("test bind string argument".to_string())),
        ),
    );

    let bind_awaitable_data = bind_callables.get("bind_test_func").unwrap();
    let (bind_awaitable, bind_arg) = bind_awaitable_data;

    bind_awaitable.call(bind_arg).await;
}

相关问题