簡體   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