Rust中serde_json序列化枚举为何输出格式不一致?
为什么
IpAddr序列化为JSON字符串,自定义枚举却输出JSON对象? 这两种输出差异的核心原因是序列化逻辑的实现方式不同:
1. std::net::IpAddr的序列化逻辑
IpAddr是Rust标准库类型,serde为它提供了定制化的Serialize实现——直接将IP地址转换成对应的字符串表示,因此序列化后输出的是JSON字符串类型。
你的示例代码及输出:
use std::net::IpAddr; fn main() { let addr : IpAddr = "127.0.0.1".parse().unwrap(); let json = serde_json::to_string(&addr).unwrap(); println!("{}", json); }
输出:
"127.0.0.1"
2. 自定义枚举的默认序列化行为
当你给自定义枚举添加#[derive(Serialize)]时,serde会使用默认的枚举序列化规则:对于带单个字段的变体,默认采用「外部标签(external tagging)」格式——将变体名称作为JSON对象的键,变体的字段值作为对应的值,因此输出是JSON对象。
你的自定义枚举示例代码及输出:
use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] enum Foo { One(String), Two(String), } fn main() { let foo = Foo::One("one".to_string()); let json = serde_json::to_string(&foo).unwrap(); println!("{}", json); }
输出:
{"One":"one"}
让自定义枚举输出JSON字符串的方法
如果想让自定义枚举和IpAddr一样输出JSON字符串,可以通过两种方式实现:
方式一:使用serde属性修改行为
如果枚举的所有变体都只包含String类型字段,可以用#[serde(into = "String")]统一转换为字符串:
use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] #[serde(into = "String")] enum Foo { One(String), Two(String), } // 需要实现从Foo到String的转换 impl From<Foo> for String { fn from(foo: Foo) -> Self { match foo { Foo::One(s) => s, Foo::Two(s) => s, } } } fn main() { let foo = Foo::One("one".to_string()); let json = serde_json::to_string(&foo).unwrap(); println!("{}", json); // 输出:"one" }
方式二:手动实现Serialize trait
直接为枚举编写定制化的序列化逻辑,和IpAddr的实现思路一致:
use serde::{Serialize, Serializer}; enum Foo { One(String), Two(String), } impl Serialize for Foo { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { // 匹配不同变体,直接序列化内部的字符串 match self { Foo::One(s) => serializer.serialize_str(s), Foo::Two(s) => serializer.serialize_str(s), } } } fn main() { let foo = Foo::One("one".to_string()); let json = serde_json::to_string(&foo).unwrap(); println!("{}", json); // 输出:"one" }
内容的提问来源于stack exchange,提问作者Shmoopy
相关产品推荐
相关产品推荐

