【问题标题】:Why is a cast needed when a closure is passed as a trait object argument?当闭包作为特征对象参数传递时,为什么需要强制转换?
【发布时间】:2018-05-25 18:54:04
【问题描述】:

我正在尝试创建一个特性,该特性应该对具有不同数量参数的函数/闭包进行抽象。像这样的:

trait MyTrait {}

impl MyTrait for Box<Fn() -> &'static str> {}

impl MyTrait for Box<Fn(u8) -> u8> {}

最初我打算这样使用它:

fn myf<F: MyTrait>(_fun: F) {}

fn main() {
    myf(Box::new(|i: u8| i + 2))
}

但此代码失败并出现错误:

error[E0277]: the trait bound `std::boxed::Box<[closure@src/main.rs:11:18: 11:31]>: MyTrait` is not satisfied

当我像这样投射盒子时,一切都会正确编译:

myf(Box::new(|i: u8| i + 2) as Box<Fn(_) -> _>)

Playground

为什么 Rust 编译器不能在没有强制转换的情况下推断出这个特征?我的方法(使用演员表)是否正确,还是有更简单的方法?我更喜欢为我的项目启用trivial_casts 警告,这种语法会触发它。

【问题讨论】:

    标签: rust closures traits


    【解决方案1】:

    这是人们容易忘记的一件事:每个闭包都是实现 Fn 的不同结构:Fn 是一个 trait,而不是一个结构,并且 trait 实现不是传递的。

    这是一个说明这一点的小例子:

    trait Base {}
    trait Derived {}
    struct Foo {}
    
    impl Base for Derived {}
    
    impl Derived for Foo {}
    
    fn myf<T>(_t: Box<T>)
    where
        T: Base + ?Sized,
    {
    }
    
    fn main() {
        let foo = Box::new(Foo {});
        //myf(foo) // does not compile
        myf(foo as Box<Derived>)
    }
    

    你真正想做的是:

    trait MyTrait {}
    
    impl<T> MyTrait for T
    where
        T: Fn() -> &'static str,
    {
    }
    
    impl<T> MyTrait for T
    where
        T: Fn(u8) -> u8,
    {
    }
    
    fn myf<F>(_fun: Box<F>)
    where
        F: MyTrait,
    {
    }
    
    fn main() {
        myf(Box::new(|i: u8| i + 2))
    }
    

    但这无法编译,因为有两个冲突的实现。

    【讨论】:

      猜你喜欢
      • 2013-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-05
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多