首页 文章

Rust Trait对象转换

提问于
浏览
3

由于此错误的两个实例,以下代码将无法编译:

错误[E0277]:特征绑定Self:std :: marker :: Sized不满足

我不明白为什么在这个实例中需要 Sized 因为 &self&Any 都是指针而且操作不需要知道实现特征的结构的大小,它只需要知道指针本身及其类型 . 转换和转换,因为 &self 在特征中实现时是通用的 .

我认为这可能是编译器强制执行不必要的约束的一个实例,我考虑过使用生锈的GitHub仓库提出问题,但我想我应该看看,如果有人在我提出问题之前知道我不知道的事情 .

use std::any::Any;

trait Component: Any {
    fn as_any(&self) -> &Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut Any {
        self
    }
}

替代方法是为实现此特征的结构创建 as_any()as_any_mut() 所需的函数,但对于这些结构,实现始终与此处显示的每个字符完全一致,从而产生相同样板代码的多个实例 .

2 回答

  • 4

    动态大小的类型也可以实现特征 . 特别是,当您定义对象安全特征时,编译器还会定义一个动态大小的类型,其名称与特征相同,这使您可以使用对象类型,例如 &Component .

    诸如 &Component&Any 之类的对象类型不仅仅是普通指针;他们是 fat pointers . 胖指针将指向数据的指针和另一个数据组合在一起:对于对象类型,它是切片的长度's a pointer to the vtable; for slices, it' .

    当从常规指针(例如 &Button )转换为对象类型时,编译器静态地知道将哪个vtable放入胖指针(例如 ButtonAny 的vtable) . 另一方面,Rust不支持从对象类型转换为另一个对象类型(例如从 &Component&Any ),因为对象中没有足够的数据来初始化新的胖指针 . 这就是编译器将此注释添加到错误消息的原因:

    = note: required for the cast to the object type `std::any::Any + 'static`
    

    有两种方法可以解决这个问题:

    • 要求实现 Component 的所有类型都是 Sized
    trait Component: Any + Sized {
        fn as_any(&self) -> &Any {
            self
        }
    
        fn as_any_mut(&mut self) -> &mut Any {
            self
        }
    }
    

    这导致您将无法使用诸如 &ComponentBox<Component> 之类的对象类型 .

    • 仅当 SelfSized 时,才使 as_anyas_any_mut 方法可用:
    trait Component: Any {
        fn as_any(&self) -> &Any
            where Self: Sized
        {
            self
        }
    
        fn as_any_mut(&mut self) -> &mut Any
            where Self: Sized
        {
            self
        }
    }
    

    这样,您仍然可以使用特征的对象类型,但是您将无法在它们上调用 as_anyas_any_mut .

  • 6

    我发现我认为是一个不需要新编译器功能的优秀解决方案 .

    pub trait Component {
        // ...
    }
    
    pub trait ComponentAny: Component + Any {
        fn as_any(&self) -> &Any;
        fn as_any_mut(&mut self) -> &mut Any;
    }
    
    impl<T> ComponentAny for T
        where T: Component + Any
    {
        fn as_any(&self) -> &Any {
            self
        }
    
        fn as_any_mut(&mut self) -> &mut Any {
            self
        }
    }
    

    从这里开始,我只需更改所有API以接受 ComponentAny 而不是 Component . 因为 Any 是针对任何 'static 类型自动实现的,所以 ComponentAny 现在自动实现为实现 Component 的任何 'static 类型 . 感谢Is there a way to combine multiple traits in order to define a new trait?的想法 .

相关问题