是否可以在闭包参数中"向下抛弃"特征对象?



我想调用一个函数指针,它本身将 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,所以即使我们尝试制作包装器函数,它也不会起作用。

最新更新