3

トレイトを実装するオブジェクトで構築できる Rust の構造体を設計しDigest、メソッドの背後にあるハッシュの動作を抽象化したいと考えています。コンパイルされない簡単な例を次に示します。

use digest::Digest;

struct Crypto<D: Digest> {
    digest: D,
}

impl<D> Crypto<D>
where
    D: Digest,
{
    pub fn hash(&self, data: &[u8]) -> Vec<u8> {
        self.digest.chain(&data).finalize_reset().to_vec()
    }
}

これselfは、メソッド シグネチャで不変に借用されるため、コンパイルに失敗します。したがって、不変に借用することはself.digestできません。そのため、代わりにそれをコピーしようとしますが、DジェネリックはCopyトレイトに準拠するように定義されていないため、失敗します。

とにかくコピーしないほうがいいです。私はむしろ1つのインスタンスが欲しいです。私が試したいくつかのこと:

  • 代わりに取得するメソッド シグネチャを変更しますmut self。しかし、それはオブジェクトの所有権をメソッドに移し、その後は再び使用できなくなります。

  • 内部可変性を採用するためにdigestフィールドをRefMutorでラップしましたが、値をコピーしようとせずに可変的に借用する正しい方法を見つけることができませんでした。また、可能であれば、コンパイル時に借用チェックを保持することをお勧めします。Celldigest

  • の型をDのインスタンスを返す関数に変更しDigest、それを使用してメソッド内で新しいダイジェストをインスタンス化しますhash()。しかし、それを と定義してもD: Box<dyn Digest>、コンパイラはthe value of the associated type OutputSize (from trait digest::Digest) must be specified. さまざまなサイズのハッシュを生成するさまざまなハッシュ アルゴリズムをサポートしたいので、これは難しいように思えます。

私はジェネリックを使用して、トレイト境界のコンパイル時の利点を得ようとしていましたが、動作に可変性が必要なオブジェクトを作成するときの内部可変性の課題が私を妨げていることを認めなければなりません。この設計課題に対する慣用的な Rust ソリューションへのポインタは大歓迎です。

to_vec()おまけ —コピーを回避し、返された配列finalize_reset()を返すにはどうすればよいですか?

4

2 に答える 2