我如何计算一个包含原始值与serde-json库串联的结构的哈希值



我需要我的结构是可哈希的。结构体在创建后永远不会改变,因此可以预先计算并将其作为字段存储。

结构体示例如下:

#[derive(Clone, Debug, Deserialize)]
pub struct Predicate {
note: Option<String>,
arguments: Option<HashMap<String, Value>>,
value: Value,
}

我试图将Hash指令添加到结构中,但Value不实现Hash

试图实现我自己

impl Hash for Value {

但是得到错误

| ^^^^^^^^^^^^^^-----
| |             |
| |             `Value` is not defined in the current crate
| impl doesn't use only types from inside the current crate

所以两个可能的解决方案对我来说就足够了

  1. 计算并存储反序列化时的哈希值,并将其保存为结构体的字段(该字段永远不会更改)
  2. Value上实现Hash-但不确定是否可以在serde板条箱之外实现。

选项1可以为我工作(在反序列化期间计算+存储)

我在文档中看到https://serde.rs/field-attrs.html#deserialize_with

#[serde(deserialize_with = "path")]

,但没有看到任何例子如何做到这一点

也许还有其他方法?

由于HashMapValue都不实现Hash,您最好的选择是手动为Predicate手动实现Hash。为了减少重复,我还建议在Value周围制作一个包装器并为此实现哈希。当你这样做的时候,确保如果a == b然后a_hashed == b_hashed。示例代码:

impl Hash for Predicate{
fn hash<H: Hasher>(&self, hasher:&mut H){
self.note.hash(hasher);
self.arguments.iter().for_each(|(key,value)|{  
//Without realizing it, I accidentally violated the contract I mentioned above
//Because there is no guarantee about the order of items returned by HashMap.iter().
//Thanks, @Jmb for pointing it out. Let this serve as a warning, be really 
//Careful when manually implementing Hash and similar traits.
key.hash(hasher);
MyValue(value).hash(hasher);    
});
MyValue(self.value).hash(hasher);
}    
}
struct MyValue(Value);
impl Hash for MyValue{
fn hash<H: Hasher>(&self, hasher:&mut H){
//large match statement here
}
}

OP提到他们可以保证对象只创建一次而不发生变异。如果是这种情况,您可以添加一个唯一标识符,例如来自UUID Crate或创建和散列的时间戳,而不是更昂贵的完整散列。

最新更新