我需要我的结构是可哈希的。结构体在创建后永远不会改变,因此可以预先计算并将其作为字段存储。
结构体示例如下:
#[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
所以两个可能的解决方案对我来说就足够了
- 计算并存储反序列化时的哈希值,并将其保存为结构体的字段(该字段永远不会更改)
- 在
Value
上实现Hash
-但不确定是否可以在serde
板条箱之外实现。
选项1可以为我工作(在反序列化期间计算+存储)
我在文档中看到https://serde.rs/field-attrs.html#deserialize_with
#[serde(deserialize_with = "path")]
,但没有看到任何例子如何做到这一点
也许还有其他方法?
由于HashMap
和Value
都不实现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或创建和散列的时间戳,而不是更昂贵的完整散列。