如何将dyn FnMut转换为自定义特征对象?

问题描述

由于Fn类特征可以多次实现,因此不能做到这一点:

trait Callable {
    fn call_me(&self);
}

impl<F,T> Callable for F
where
    F: Fn(T),T: Default,{
    fn call_me(&self) {
        self(T::default())
    }
}

我想做这样的事情,所以我尝试使用特质对象,因为我可以为它们实现特质:

impl<T> Callable for dyn Fn(T)
where
    T: Default,{
    fn call_me(&self,_: &Env) {
        self(T::default())
    }
}

这可行,但是我想为回调系统存储各种Callable。我的第一个也是最好的尝试是使用Vec<Box<dyn Callable>>,但似乎无法将特征对象转换为它们实现的特征的特征对象。

trait Callable {
    fn call_me(&self);
}

impl<T> Callable for dyn Fn(T)
where
    T: Default,{
    fn call_me(&self) {
        self(T::default())
    }
}

impl<T> Callable for &dyn Fn(T)
where
    T: Default,{
    fn call_me(&self) {
        self(T::default())
    }
}

fn main() {
    let f = |n: i32| println!("n = {}",n);

    // fine,obvIoUsly
    f(i32::default());

    // also fine
    let bf = Box::new(f) as Box<dyn Fn(i32)>;
    bf(i32::default());

    // works if Callback implemented for &dyn Fn(T)
    // but only works on references Now
    let bfc = &bf.as_ref() as &dyn Callable;
    bfc.call_me();

    // does not work
    let callbacks: Vec<Box<dyn Callable>> = vec![bf as Box<dyn Callable>];
}

这给了我

error[E0605]: non-primitive cast: `std::Boxed::Box<dyn std::ops::Fn(i32)>` as `std::Boxed::Box<dyn Callable>`
  --> src/main.rs:39:50
   |
39 |     let callbacks: Vec<Box<dyn Callable>> = vec![bf as Box<dyn Callable>];
   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object

我不明白。特质对象是类型,我为所有Callable特征对象都实现了Fn(T),通常可以从特定的已实现特征对象中强制执行。

  • 为什么不起作用?
  • 解决方法吗?
  • 为什么Fn traits参数类型是通用的却没有关联?

旁注

我想要一种这样的系统,以便存储任何可以从环境中获取参数的闭包(不仅是函数),而与参数的数量和类型无关。

trait FromEnv {
    fn from_env(env: &Env) -> Self;
}

trait Callable {
    fn call_me(&self,env: &Env);
}

impl<T> Callable for Fn(T)
where
    T: FromEnv,env: &Env) {
        self(T::from_env(env))
    }
}

// same kind of impl for Fn(T,U,...,Z)

我知道我可以做到

  • 允许使用&Env并允许用户处理“提取”的闭包。
  • 使用宏创建自己的自定义闭包类型,该类型直接实现Callable

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)