You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 21:12:45