如何使用serde将具有不可序列化键的HashMap序列化?

3

我有一个HashMap作为一个结构体的值,我正在手动序列化:

pub struct GitInfo {
    pub branches: HashMap<Oid, Branch>,
}

Branch是我定义的内容,但Oid是一个外部类型,我没有所有权,它有一个to_string()方法,我很乐意使用它...

我已经阅读了如何使用Serde将带有结构体作为键的HashMap序列化为JSON?,但它引用了作者定义的键 - 我无法为Oid实现Serialize,因为它不在我的crate中。同样的原因,我也无法为HashMap<Oid,Branch>实现Serialize

有什么解决办法吗?我可以在HashMap<Oid,Branch>周围构建一个包装器结构体,但这似乎有些过度设计。

有人建议我查看如何使用Serde在序列化期间转换字段?如何使用现有的Display trait实现来实现Serialize? - 这两者似乎都归结为使用serialize_with - 我可能可以这样做,但我必须使用derive(Serialize)宏,而我原本计划手动序列化GitInfo(见下文)。或者我可以使用包装对象。

如果这些是唯一的选项,我可以接受,但似乎有点令人惊讶,没有更简单的方法 - 是否有一种方式可以从我的GitInfo序列化中调用像serialize_with宏使用的函数呢?

例如:

impl Serialize for GitInfo {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut state = serializer.serialize_struct("GitInfo", 2)?;
        state.serialize_field("other bits", &self.other_bits)?;
        state.serialize_field("branches", /* something */)?;
        state.end()
    }
}

为什么你使用 serialize_field 而不是 serialize_map - undefined
我正在对一个包含HashMap字段的结构体GitInfo进行序列化。因此,我正在使用serialize_struct方法,该方法返回一个没有serialize_map方法的SerializeStruct对象。如果有一种方法可以调用serialize_map来创建一个新的序列化版本的HashMap,然后将结果作为参数插入到serialize_field中,那就太棒了 - 但是我还没有找到这样的方法。 - undefined
1个回答

0
在将HashMap<Oid, Branch>存储在GitInfo结构中时,您不需要构建一个包装器结构。但是,在以自定义方式序列化HashMap时,您需要使用一个包装器结构。您可以在Serialize实现中定义新的包装器结构,以指示它仅用于序列化。
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        struct Branches<'a>(&'a HashMap<Oid, Branch>);

        impl Serialize for Branches<'_> {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: Serializer,
            {
                let mut map = serializer.serialize_map(Some(self.0.len()))?;
                for (oid, branch) in self.0 {
                    map.serialize_entry(&oid.to_string(), &branch)?;
                }
                map.end()
            }
        }

        let mut state = serializer.serialize_struct("GitInfo", 2)?;
        state.serialize_field("branches", &Branches(&self.branches))?;
        state.serialize_field("other bits", &self.other_bits)?;
        state.end()
    }
}

这里有一个展示这个解决方案基本实现的playground
请注意,由serialize_with生成的代码遵循相同的模式:它定义了一个新类型的包装结构体,并提供了一个Serialize实现,在这个特性实现中,它调用了您提供的函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接