繁体   English   中英

如何在结构中使用大小特征?

[英]How to use sized traits in structs?

我正在尝试使用 AES crate,它提供三种算法:AES128、AES192 和 AES256。 我正在尝试创建一个结构,该结构可以通过检测密钥大小来创建正确的算法,并将其保存以备后用。

我看到它们都实现了 BlockEncrypt(我只需要加密)特性,但是当我尝试使用这种类型在结构中创建一个字段时,即使提供了大小,我也得到了一个“特性BlockEncrypt无法制作成 object。该特征不能变成 object 因为它需要Self: Sized " 错误。

pub struct MyStruct<'a, T: Sized> {
       ciph: Box< dyn BlockEncrypt<BlockSize = T>>,
}

Sized作为超类型的特征不是“对象安全”的,这意味着使用dyn的动态调度在这些类型的特征上是不可能的。

您可以通过为您想要处理的每种可能类型使用一个枚举,并结合一个宏,该宏将巧妙地生成动态调度每个枚举可能性所需的所有match臂,从而相对简洁地完成此操作。

为了便于解释,为了让事情变得简单,我将定义一个新特征(使用Sized超类型),以便这个答案不依赖于特定的板条箱:

trait SampleTrait: Sized {
    fn method_a(&self, foo: &str);
    fn method_b(&self, foo: i32, bar: String) -> String;
}

现在我们至少需要这个特征的两个实现来演示解决方案:

struct ImplA;
struct ImplB;

impl SampleTrait for ImplA {
    fn method_a(&self, foo: &str) {
        println!("<ImplA as SampleTrait>::method_a(): {:?}", foo);
    }
    
    fn method_b(&self, foo: i32, bar: String) -> String {
        println!("<ImplA as SampleTrait>::method_b(): {:?} {:?}", foo, bar);
        format!("from ImplA: {}", bar)
    }
}

impl SampleTrait for ImplB {
    fn method_a(&self, foo: &str) {
        println!("<ImplB as SampleTrait>::method_a(): {:?}", foo);
    }
    
    fn method_b(&self, foo: i32, bar: String) -> String {
        println!("<ImplB as SampleTrait>::method_b(): {:?} {:?}", foo, bar);
        format!("from ImplB: {}", bar)
    }
}

枚举只需要最少需要处理的每种可能类型:

enum DynSampleTrait {
    ImplA(ImplA),
    ImplB(ImplB),
}

现在要对此进行调度,您必须执行以下操作:

match value {
    DynSampleTrait::ImplA(v) => v.method_a("something"),
    DynSampleTrait::ImplB(v) => v.method_a("something"),
}

为了避免不得不重复我们自己,让我们声明一个将为我们生成整个match的宏:

macro_rules! dyn_sample_trait_call {
    (($m:expr) $v:ident => $code:block) => {
        match $m {
            DynSampleTrait::ImplA($v) => $code,
            DynSampleTrait::ImplB($v) => $code,
        }
    }
}

现在我们可以像这样使用宏:

dyn_sample_trait_call!((value) v => { v.method_a("something") })

value进入匹配表达式, v是展开枚举可能性所持有的内部值的标识符。 这些是分开的,因此如果您不想使用拥有的DynSampleTrait ,您可以匹配参考:

dyn_sample_trait_call!((&value) v => { v.method_a("something") })

游乐场

正如@cdhowie 提到的,您不能从具有Sized边界的特征创建特征 object。 相反,您可以创建一个枚举:

enum MyAlgorithm {
    AES128(AES128),
    AES192(AES192),
    AES256(AES256),
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM