Wes*_*tum 6 traits rust associated-types
我对 Rust 很陌生,所以我可能会混淆术语。
我想使用hashes crate 做一些散列,我想动态地选择在运行时使用哪种算法(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...
};
Run Code Online (Sandbox Code Playgroud)
我有点明白这是行不通的,因为Digest没有指定所需的关联类型。如果我尝试填写它们:
"sha256" => Box::new(Sha256::new()) as Box<Digest<<OutputSize = U32, BlockSize = U64>>>,
Run Code Online (Sandbox Code Playgroud)
我留下了一个错误:the trait 'digest::Digest' cannot be made into an object。我认为这种方法无论如何都会失败,因为match在不同算法具有不同关联类型的情况下,返回的类型略有不同。
我错过了一些明显的东西吗?如何动态创建实现 trait 的东西的实例,然后保留那个东西并通过 trait 接口使用它?
The message refers to object safety (longer article). The Digest trait has two incompatibilities:
Digest objects).fn result(self) -> …) taking self by value. You won't be able to call it, which ruins usability of this trait.Once a trait object is created, information about its subtype-specific features such as memory layout or associated types is erased. All calls to the trait object's methods are done via a vtable pointer. This means they all must be compatible, and Rust can't allow you to call any methods that could vary in these aspects.
A workaround is to create your custom wrapper trait/adapter that is object-compatible. I'm not sure if that's the best implementation, but it does work:
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();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1671 次 |
| 最近记录: |