1

由于Fn-like 特征可以多次实现,因此不能这样做:

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这行得通,但我想为回调系统存储各种。我的第一个也是最好的尝试是使用 a 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特征参数类型是通用的且不相关的,这是有原因的吗?

边注

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

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,
{
    fn call_me(&self, env: &Env) {
        self(T::from_env(env))
    }
}

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

我知道我可以:

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

0 回答 0