如何对具有关联类型的特征进行装箱? [英] How to Box a trait that has associated types?

查看:71
本文介绍了如何对具有关联类型的特征进行装箱?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对Rust还是很陌生,所以我可能对术语感到困惑.

I'm very new to Rust so I may have terminology confused.

我想使用哈希板条箱进行一些哈希处理,并且我想动态选择哪种算法(sha256,sha512等)在运行时使用.

I want to use the hashes crates to do some hashing and I want to dynamically pick which algorithm (sha256, sha512, etc.) to use at runtime.

我想写这样的东西:

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所需的关联类型,我有点不起作用.如果我尝试填写它们:

I sort of get that that doesn't work because the associated types required by Digest aren't specified. If I attempt to fill them in:

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

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

I'm left with an error: the trait 'digest::Digest' cannot be made into an object. I think this approach will fail anyway because match will be returning slightly different types in cases where different algorithms have different associated types.

我缺少明显的东西吗?我该如何动态地创建实现特质的事物的实例,然后保留该事物并通过trait接口使用它?

Am I missing something obvious? How can I dynamically create an instance of something that implements a trait and then hold on to that thing and use it through the trait interface?

推荐答案

该消息引用了较长的文章). Digest特征有两个不兼容之处:

The message refers to object safety (longer article). The Digest trait has two incompatibilities:

  1. It uses associated types (this can be worked around by explicitly setting all type parameters to values compatible for all Digest objects).
  2. It has a method (fn result(self) -> …) taking self by value. You won't be able to call it, which ruins usability of this trait.

一旦创建了特征对象,就将删除有关其特定于子类型的功能(如内存布局或关联的类型)的信息.对trait对象的方法的所有调用都是通过vtable指针完成的.这意味着它们都必须兼容,Rust不允许您调用在这些方面可能有所不同的任何方法.

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();
}

这篇关于如何对具有关联类型的特征进行装箱?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆