Rust结构体字段如何支持字符串或数字多类型?
在Rust中实现支持字符串或数字的结构体字段
你的问题出在默认的Serde枚举序列化/反序列化规则上:默认情况下,Serde会把枚举序列化为带变体名称的结构化JSON(比如{"CouldBeAString": "your_value"}),但外部API的thing字段是直接的原始值(要么是字符串要么是数字),没有变体标签,所以反序列化时会报错。
解决方法是给枚举加上#[serde(untagged)]属性,让Serde自动尝试用不同的枚举变体去匹配输入的JSON值,不需要显式的标签。
完整实现代码
use serde::{Deserialize, Serialize}; // 给枚举添加untagged属性,让Serde自动匹配类型 #[derive(Debug, Deserialize, Serialize)] #[serde(untagged)] pub enum Thing { Number(u8), String(String), } #[derive(Debug, Deserialize, Serialize)] struct ExternalApiThing { thing: Thing, } fn main() -> Result<(), Box<dyn std::error::Error>> { // 测试反序列化字符串类型的thing let json_str = r#"{"thing": "hello world"}"#; let data: ExternalApiThing = serde_json::from_str(json_str)?; println!("反序列化字符串结果: {:?}", data); // 测试反序列化数字类型的thing let json_num = r#"{"thing": 42}"#; let data_num: ExternalApiThing = serde_json::from_str(json_num)?; println!("反序列化数字结果: {:?}", data_num); // 测试序列化 let output = ExternalApiThing { thing: Thing::String("test".to_string()), }; println!("序列化字符串结果: {}", serde_json::to_string(&output)?); let output_num = ExternalApiThing { thing: Thing::Number(100), }; println!("序列化数字结果: {}", serde_json::to_string(&output_num)?); Ok(()) }
关键说明
#[serde(untagged)]:这个属性告诉Serde,不要期望JSON里有枚举变体的标签,而是直接尝试将JSON值与枚举的各个变体匹配(按定义顺序尝试,所以如果有类型重叠的情况要注意顺序,比如i32和f64,要把更具体的放在前面)。- 类型适配:如果API返回的数字不是
u8(比如是i32、f64),直接修改枚举里的数字类型即可,比如Number(i32)或者Number(f64)。 - 序列化效果:添加这个属性后,序列化时也会直接输出原始值,而不是带标签的结构,符合外部API的格式要求。
注意事项
如果JSON值同时能匹配多个变体(比如字符串"123"既可以解析为字符串,也可以尝试解析为数字),Serde会优先匹配枚举中定义在前的变体。如果需要优先匹配数字,可以把Number变体放在String前面。
内容的提问来源于stack exchange,提问作者Seth Lutske
相关产品推荐
相关产品推荐

