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

lmvvr0a8  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(111)

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

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

字符串
Branch是我定义的,但Oid是我不拥有的外部类型,我很乐意使用to_string()方法。
我读过How do I use Serde to serialize a HashMap with structs as keys to JSON?,但它引用了作者定义的键-我不能为Oid实现Serialize,因为它不在我的crate中。出于类似的原因,我不能为HashMap<Oid, Branch>实现Serialize
有什么方法可以解决这个问题吗?我可以围绕HashMap<Oid, Branch>构建一个 Package 器结构体,但这似乎有点大材小用。
有人建议我使用How to transform fields during serialization using Serde?How can I implement Serialize using an existing Display trait implementation?--这两种方法似乎都可以归结为使用serialize_with--我也可以这样做,但是当我计划手动序列化GitInfo时,我必须使用derive(Serialize)宏(见下文)。
如果这些是唯一的选择,我可以接受它,但似乎有点令人惊讶的是,没有一个更简单的方法-有没有一些方法来调用像serialize_with宏使用的函数,但从我的GitInfo序列化?
比如说:

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()
    }
}

h7appiyu

h7appiyu1#

当将HashMap<Oid, Branch>存储在GitInfo结构中时,您不需要围绕HashMap<Oid, Branch>构建 Package 器结构,但当以自定义方式序列化HashMap时,您将需要使用 Package 器结构。您可以在Serialize实现中定义新的 Package 器结构,以指示它应仅用于序列化。

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生成的代码遵循相同的模式:它定义了一个newtype Package 器结构沿着Serialize实现,并在trait实现中调用您提供的函数。

相关问题