由于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
。