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

Rust中如何将互斥分析结构体扁平化合并为Analysis结构体?

Rust 实现带扁平化专属字段的强类型 Analysis 结构体方案

核心思路

要实现类似 TypeScript 联合类型的强绑定效果,同时让专属字段扁平化到顶层(解决 OpenAPI 文档嵌套问题),我们可以通过带固定类型标识的子结构体 + 无标签枚举的组合方案实现,既保证类型严格匹配,又满足序列化/文档的扁平化需求。

1. 依赖准备

确保 Cargo.toml 中包含必要依赖:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
chrono = { version = "0.4", features = ["serde", "utc"] }
schemars = { version = "0.8", features = ["chrono"] } # 用于生成符合规范的 OpenAPI 文档

2. 代码实现

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

// 定义分析类型的固定枚举,序列化时自动转为蛇形命名
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum AnalysisType {
    Chemical,
    Physical,
    Biological,
}

// 用宏提取公共字段,避免重复代码
macro_rules! analysis_common_fields {
    () => {
        pub id: String,
        pub name: String,
        pub created: DateTime<Utc>,
        pub modified: DateTime<Utc>,
    };
}

// 化学分析结构体:公共字段 + 专属字段 + 固定类型标识
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct ChemicalAnalysis {
    analysis_common_fields!(),
    #[serde(rename = "analysis_type")]
    pub analysis_type: AnalysisType,
    pub ph_level: f32,
    pub chemical_composition: String,
}

// 物理分析结构体
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct PhysicalAnalysis {
    analysis_common_fields!(),
    #[serde(rename = "analysis_type")]
    pub analysis_type: AnalysisType,
    pub temperature: f32,
    pub pressure: f32,
}

// 生物分析结构体
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
pub struct BiologicalAnalysis {
    analysis_common_fields!(),
    #[serde(rename = "analysis_type")]
    pub analysis_type: AnalysisType,
    pub organism_type: String,
    pub cell_count: u32,
}

// 无标签枚举作为联合类型,serde 会自动根据字段匹配对应变体
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(untagged)]
pub enum Analysis {
    Chemical(ChemicalAnalysis),
    Physical(PhysicalAnalysis),
    Biological(BiologicalAnalysis),
}

// 为子结构体添加构造函数,强制绑定固定的 analysis_type
impl ChemicalAnalysis {
    pub fn new(
        id: String,
        name: String,
        created: DateTime<Utc>,
        modified: DateTime<Utc>,
        ph_level: f32,
        chemical_composition: String,
    ) -> Self {
        Self {
            id,
            name,
            created,
            modified,
            analysis_type: AnalysisType::Chemical,
            ph_level,
            chemical_composition,
        }
    }
}

// 同理为 PhysicalAnalysis、BiologicalAnalysis 添加构造函数

3. 方案优势

  • 字段扁平化:序列化后所有字段(公共、类型标识、专属)都在顶层,不会出现枚举变体的嵌套键,完全符合 OpenAPI 文档的扁平化需求。
  • 类型严格匹配:通过构造函数强制每个子结构体的 analysis_type 与自身类型绑定,不会出现类型不匹配的情况,实现类似 TypeScript 联合类型的强约束。
  • 自动序列化/反序列化:无标签枚举让 serde 自动根据 analysis_type 值匹配对应变体,反序列化时字段不匹配会直接返回错误,保证数据安全。
  • 标准 OpenAPI 文档:schemars 会自动生成 oneOf 类型的 schema,前端看到的结构与 TypeScript 联合类型完全一致。

4. 序列化示例

fn main() {
    let chemical = ChemicalAnalysis::new(
        "test-123".to_string(),
        "饮用水质检测".to_string(),
        Utc::now(),
        Utc::now(),
        7.2,
        "H2O, NaCl".to_string(),
    );

    let analysis = Analysis::Chemical(chemical);
    let json = serde_json::to_string_pretty(&analysis).unwrap();
    println!("{}", json);
}

输出的 JSON 完全扁平化:

{
  "id": "test-123",
  "name": "饮用水质检测",
  "created": "2024-05-20T14:30:00Z",
  "modified": "2024-05-20T14:30:00Z",
  "analysis_type": "chemical",
  "ph_level": 7.2,
  "chemical_composition": "H2O, NaCl"
}

内容的提问来源于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.06 16:32:51