gpt4 book ai didi

generics - 如何在 Rust 中使用泛型类型的内部可变性?

转载 作者:行者123 更新时间:2023-12-03 11:25:48 26 4
gpt4 key购买 nike

我想用 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特性,它失败了。

无论如何,我宁愿不复制它。我宁愿有一个实例。我尝试过的一些事情:

  • 更改方法签名以获取 mut self反而。但这会将对象的所有权转移到方法中,之后就不能再使用了。

  • 包装 digest RefMut 中的字段或 Cell ,努力采用internal mutability , 但我无法找出正确的方法来借用 digest可变而不试图复制值。此外,如果可能的话,更愿意在编译时保留借用检查。

  • 更改 D 的类型到返回 Digest 实例的函数,并用它在 hash() 中实例化一个新的摘要方法。但是,即使我将其定义为 D: Box<dyn Digest> ,编译器提示 the value of the associated type OutputSize (from trait digest::Digest) must be specified .所以这看起来很有挑战性,因为我想支持不同的哈希算法,这些算法会产生不同大小的哈希值。

我试图使用泛型来获得特征边界的编译时优势,但不得不承认,在与行为需要可变性的对象组合时,内部可变性的挑战阻碍了我。非常感谢指出针对此设计挑战的惯用 Rust 解决方案。

奖励——我如何避免 to_vec()复制并返回 the array returned by finalize_reset()

最佳答案

I'd rather not copy it, anyway. I'd rather have the one instance [of self.digest].

问题是 self.digest.chain() 消费(拥有)self.digest ,这是 Digest::chain() 契约(Contract)的基本部分你不能改变。内部可变性无济于事,因为它不是可变性问题,而是对象生命周期问题 - 在对象被移动或删除后您无法使用它。

你的创意digest不过,创建摘要的函数应该可以工作。它将需要两种泛型类型,一种用于摘要类型,特征界限为 Digest ,另一个用于工厂,特征界限为 Fn() -> D :

struct Crypto<F> {
digest_factory: F,
}

impl<D, F> Crypto<F>
where
D: Digest,
F: Fn() -> D,
{
pub fn hash(&self, data: &[u8]) -> Vec<u8> {
(self.digest_factory)()
.chain(&data)
.finalize() // use finalize as the object is not reused
.to_vec()
}
}

how do I avoid the to_vec() copy and just return the array returned by finalize_reset()?

你可以有hash()返回与 finalize() 相同的类型, digest::Output<D> :

pub fn hash(&self, data: &[u8]) -> digest::Output<D> {
(self.digest_factory)()
.chain(&data)
.finalize()
}

关于generics - 如何在 Rust 中使用泛型类型的内部可变性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65783417/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com