我对Rust很新,所以我的术语可能很混乱 .
我想使用hashes crates进行一些散列,我想动态选择在运行时使用哪种算法(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
将返回稍微不同的类型 .
我错过了一些明显的东西吗如何动态创建实现特征的事物的实例,然后坚持该事物并通过特征界面使用它?
1 回答
该消息引用object safety(longer article) . Digest trait有两个不兼容性:
It uses associated types(这可以通过将所有类型参数显式设置为与所有
Digest
对象兼容的值来解决) .它有一个方法(
fn result(self) -> …
)按值self
. 你将无法调用它,这会破坏这种特性的可用性 .创建特征对象后,将删除有关其特定于子类型的特征(如内存布局或关联类型)的信息 . 对特征对象方法的所有调用都是通过vtable指针完成的 . 这意味着它们都必须兼容,并且Rust不允许您调用任何可能在这些方面有所不同的方法 .
解决方法是创建与对象兼容的自定义包装器特征/适配器 . 我不确定这是否是最好的实现,但它确实有效: