Rust 如何框选具有关联类型的特征?

Rust 如何框选具有关联类型的特征?,rust,traits,associated-types,Rust,Traits,Associated Types,我对生锈很陌生,所以我可能把术语弄糊涂了 我想使用板条箱来做一些散列,我想动态选择在运行时使用哪个算法(sha256、sha512等) 我想这样写: let hasher = match "one of the algorithms" { "sha256" => Box::new(Sha256::new()) as Box<Digest>, "sha512" => Box::new(Sha512::new()) as Box<Digest>

我对生锈很陌生,所以我可能把术语弄糊涂了

我想使用板条箱来做一些散列,我想动态选择在运行时使用哪个算法(sha256、sha512等)

我想这样写:

let hasher = match "one of the algorithms" {
    "sha256" => Box::new(Sha256::new()) as Box<Digest>,
    "sha512" => Box::new(Sha512::new()) as Box<Digest>
    // etc...
};
我留下了一个错误:
无法将trait'digest::digest'制作成对象
。我认为这种方法无论如何都会失败,因为在不同算法具有不同关联类型的情况下,
match
将返回稍微不同的类型

我错过了什么明显的东西吗?如何动态地创建实现某个特性的某个对象的实例,然后保留该对象并通过trait接口使用它?

消息引用()。有两个不兼容:

  • 它(可以通过显式地将所有类型参数设置为与所有
    摘要
    对象兼容的值来解决这个问题)
  • 它有一个方法(
    fn result(self)->…
    )按值获取
    self
    。您将无法调用它,这将破坏此特性的可用性
  • 创建特征对象后,有关其子类型特定功能(如内存布局或关联类型)的信息将被删除。所有对trait对象方法的调用都是通过vtable指针完成的。这意味着它们都必须兼容,Rust不允许您调用在这些方面可能不同的任何方法

    解决方法是创建与对象兼容的自定义包装器/适配器。我不确定这是否是最好的实现,但它确实有效:

    trait Digest {
        type Assoc;
        fn result(self);
    }
    
    struct Sha;
    
    impl Digest for Sha {
        type Assoc = u8;
        fn result(self) {}
    }
    
    ///////////////////////////////////////////
    
    trait MyWrapper {
        fn result(&mut self); // can't be self/Sized
    }
    
    impl<T: Digest> MyWrapper for Option<T> {
        fn result(&mut self) {
            // Option::take() gives owned from non-owned
            self.take().unwrap().result() 
        }
    }
    
    fn main() {
        let mut digest: Box<MyWrapper> = Box::new(Some(Sha));
        digest.result();
    }
    
    trait摘要{
    类型协会;
    fn结果(自我);
    }
    结构Sha;
    Sha的impl摘要{
    类型Assoc=u8;
    fn结果(自){}
    }
    ///////////////////////////////////////////
    特征MyWrapper{
    fn结果(&mut self);//不能为自/大小
    }
    impl MyWrapper for Option{
    fn结果(&mut self){
    //Option::take()从非所有者中提供所有者
    self.take().unwrap().result()
    }
    }
    fn main(){
    让mut消化:Box=Box::new(Some(Sha));
    digest.result();
    }
    
    您可以创建一个包装器类型和一个您自己的特性,实现您实际需要的接口,而无需关联类型。把这样一个特性包装起来会有用的。相关:@user4815162342我认为这是值得回答的。我想知道一个人是否可以把
    结果
    作为接受
    自我:框
    作为一个工具来实现。这样就不再需要
    选项
    ,并且可以恢复编译时对调用
    结果
    两次的阻止。
    trait Digest {
        type Assoc;
        fn result(self);
    }
    
    struct Sha;
    
    impl Digest for Sha {
        type Assoc = u8;
        fn result(self) {}
    }
    
    ///////////////////////////////////////////
    
    trait MyWrapper {
        fn result(&mut self); // can't be self/Sized
    }
    
    impl<T: Digest> MyWrapper for Option<T> {
        fn result(&mut self) {
            // Option::take() gives owned from non-owned
            self.take().unwrap().result() 
        }
    }
    
    fn main() {
        let mut digest: Box<MyWrapper> = Box::new(Some(Sha));
        digest.result();
    }