如何包装具有相关类型的特征?

问题描述 投票:3回答:1

我是Rust的新手,所以我的术语很混乱。

我想使用hashes板条箱进行一些散列,我想动态选择在运行时使用哪种算法(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...
};

我认为这不起作用,因为没有指定Digest所需的相关类型。如果我试图填写他们:

"sha256" => Box::new(Sha256::new()) as Box<Digest<<OutputSize = U32, BlockSize = U64>>>,

我留下了一个错误:the trait 'digest::Digest' cannot be made into an object。我认为这种方法无论如何都会失败,因为在不同算法具有不同关联类型的情况下,match将返回稍微不同的类型。

我错过了一些明显的东西吗如何动态创建实现特征的事物的实例,然后坚持该事物并通过特征界面使用它?

rust traits associated-types
1个回答
2
投票

该消息指的是object safetylonger article)。 Digest trait有两个不兼容性:

  1. uses associated types(这可以通过明确地将所有类型参数设置为与所有Digest对象兼容的值来解决)。
  2. 它有一个方法(fn result(self) -> …)按价值取self。你将无法调用它,这会破坏这种特性的可用性。

创建特征对象后,将删除有关其特定于子类型的功能(如内存布局或关联类型)的信息。对特征对象方法的所有调用都是通过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();
}
© www.soinside.com 2019 - 2024. All rights reserved.