[英]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.