Rust Serde自定义序列化:String转&'static str及动态键名需求
如何用Serde实现动态键的自定义序列化
我需要将如下定义的Data结构体序列化为以key字段值为键、value字段值为值的JSON对象,而不是默认的包含key和value两个固定字段的结构。
原代码:
use serde::ser::{Serialize, Serializer, SerializeStruct}; struct Data { key: String, // 或 &str value: i32, } impl Serialize for Data { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { let mut state = serializer.serialize_struct("Data", 1)?; // 尝试用动态key但出现生命周期错误 // let key = (&self.key).to_string(); // state.serialize_field(&*key, &self.value)?; state.serialize_field("key", &self.value)?; state.end() } } fn main() { let data = Data { key: String::from("age"), value: 21, }; let json = serde_json::to_string_pretty(&data).unwrap(); println!("the JSON is: {}", json) }
默认序列化结果:
{ "key": "age", "value": 21 }
期望的序列化结果:
{ "age": 21 }
核心思路
Serde的serialize_struct适用于编译期固定字段名的结构体序列化,而动态键值对的场景应该使用serialize_map方法——因为JSON对象本质是键值对映射,而非固定字段的结构体。
针对String类型key的实现
use serde::{Serialize, Serializer}; use serde_json; struct Data { key: String, value: i32, } impl Serialize for Data { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { // 创建包含1个键值对的map序列化状态 let mut map = serializer.serialize_map(Some(1))?; // 插入动态键与对应的值 map.serialize_entry(&self.key, &self.value)?; map.end() } } fn main() { let data = Data { key: String::from("age"), value: 21, }; let json = serde_json::to_string_pretty(&data).unwrap(); println!("{}", json); }
针对&str类型key的实现(含生命周期)
如果Data的key是引用类型,需要正确标注生命周期以避免错误:
use serde::{Serialize, Serializer}; use serde_json; struct Data<'a> { key: &'a str, value: i32, } impl<'a> Serialize for Data<'a> { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { let mut map = serializer.serialize_map(Some(1))?; map.serialize_entry(self.key, &self.value)?; map.end() } } fn main() { let data = Data { key: "age", value: 21, }; let json = serde_json::to_string_pretty(&data).unwrap(); println!("{}", json); }
原代码报错原因
原代码尝试用serialize_struct传入动态生成的String作为字段名时,serialize_field要求字段名的生命周期至少覆盖序列化器的整个操作周期。但临时创建的String会在当前作用域结束后被释放,无法满足生命周期要求。而serialize_map的serialize_entry方法对键的生命周期要求更灵活,只要键在序列化过程中有效即可,完美适配动态生成的键场景。
内容的提问来源于stack exchange,提问作者Mohit Saini
相关产品推荐
相关产品推荐

