我想调用一个函数指针,它本身将 trait 对象作为参数:
fn invoke(x: &Fn(&WithFoo), y: &MyStruct) {
// MyStruct implements WithFoo
x(y);
}
目前为止,一切都好。现在,我遇到的问题是如何使用带有签名的函数指针来调用它,例如&Fn(&WithFooBar)
特征WithFooBar
继承自WithFoo
。
这是我尝试执行此操作的示例代码:
trait WithFoo {
fn foo(&self);
}
trait WithFooBar: WithFoo {
fn bar(&self);
}
struct MyStruct {
}
impl WithFoo for MyStruct {
fn foo(&self) {
println!("foo");
}
}
impl WithFooBar for MyStruct {
fn bar(&self) {
println!("bar");
}
}
fn foobar_caller(wf: &WithFooBar) {
wf.foo();
wf.bar();
}
fn invoke(x: &Fn(&WithFoo), y: &MyStruct) {
x(y);
}
fn main() {
let data = MyStruct {};
invoke(&foobar_caller,&data);
}
此操作失败,并显示以下编译错误:
error: type mismatch: the type `fn(&WithFooBar) {foobar_caller}` implements the trait `for<'r> std::ops::Fn<(&'r WithFooBar + 'r,)>`, but the trait `for<'r> std::ops::Fn<(&'r WithFoo + 'r,)>` is required (expected trait `WithFoo`, found trait `WithFooBar`) [--explain E0281]
我知道错误是说&Fn(&WithFooBar)
不是&Fn(&WithFoo)
,但考虑到WithFooBar
特征继承自WithFoo
,似乎应该可以传递指向此函数的指针。
是否可以以某种方式"向下投射"函数指针以键入 &Fn(&WithFoo)
?我已经尝试了这两种方法:
let f = &foobar_caller as &Fn(&WithFoo);
invoke(f,&data);
而这个:
let f: &Fn(&WithFoo) = &foobar_caller;
invoke(f,&data);
但这些尝试都没有奏效。
(这个例子在这里的锈操场上。
不,你不能这样做。首先,Rust 不支持将一个 trait 对象向下转换为另一个 trait 对象。使用 Any
特征,您可以将 trait 对象向下转换为底层对象的具体类型,然后获取不同类型的 trait 对象,但这需要知道对象的具体类型,而您不知道 - 这就是 trait 对象的全部意义!
此外,你试图做的是不合理的:一个期望接收&WithFooBar
的函数不应该传递一个&WithFoo
,因为WithFoo
可能无法实现WithFooBar
。如果反过来,它会是合理的,但即使WithFooBar
继承自WithFoo
,Rust 也不允许将&WithFooBar
转换为&WithFoo
,所以即使我们尝试制作包装器函数,它也不会起作用。