如何用Serde将多个Vec序列化为单个JSON数组?
解决方案
核心思路
先把workspace和methods的元素合并为一个统一的可序列化集合,再一次性将这个集合序列化为resources字段,彻底避免重复调用serialize_field导致的覆盖问题。
具体实现
假设Workspace和Request已实现Serialize trait,以下是完整代码示例:
1. 定义基础结构体
use serde::{Serialize, Serializer}; use serde::ser::SerializeStruct; #[derive(Serialize)] struct Workspace<'a> { name: &'a str, // 其他业务字段 } #[derive(Serialize)] struct Request<'a> { path: &'a str, // 其他业务字段 } struct Base<'a> { workspace: Vec<Workspace<'a>>, methods: Vec<Request<'a>>, // 其他可选字段 }
2. 为Base实现Serialize trait
impl<'a> Serialize for Base<'a> { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { // 初始化结构体序列化器,参数为结构体名称和字段总数(含其他字段需调整数值) let mut state = serializer.serialize_struct("Base", 1)?; // 合并两个Vec的迭代器,转换为统一类型的集合 let resources = self.workspace.iter() .chain(self.methods.iter()) .collect::<Vec<_>>(); // 一次性序列化合并后的集合作为resources字段 state.serialize_field("resources", &resources)?; // 完成结构体序列化 state.end() } }
进阶优化(避免额外内存分配)
如果不想通过collect分配新的Vec,可以自定义一个枚举类型包装两种元素,为枚举实现Serialize后直接使用迭代器序列化:
// 自定义枚举统一两种元素类型 enum Resource<'a> { Workspace(&'a Workspace<'a>), Request(&'a Request<'a>), } impl<'a> Serialize for Resource<'a> { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { match self { Resource::Workspace(w) => w.serialize(serializer), Resource::Request(r) => r.serialize(serializer), } } } // 调整Base的Serialize实现 impl<'a> Serialize for Base<'a> { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { let mut state = serializer.serialize_struct("Base", 1)?; // 直接生成枚举迭代器,无需分配新Vec let resources = self.workspace.iter().map(Resource::Workspace) .chain(self.methods.iter().map(Resource::Request)); state.serialize_field("resources", &resources.collect::<Vec<_>>())?; state.end() } }
内容的提问来源于stack exchange,提问作者Rushmore75
相关产品推荐
相关产品推荐

