如何使用Serde反序列化嵌套结构体形式的JSON与YAML数据?
问题分析与解决方案
你的初始代码无法反序列化的核心原因是:JSON/YAML中scjson数组的每个元素并不是直接的StateMachine对象,而是一个以"StateMachine"为键、包裹着StateMachine实例的对象。同时,最终YAML里的各类状态(AtomicState、ParallelState等)属于标签式的多态结构,需要用枚举来处理。
1. 基础JSON反序列化修正
针对你给出的JSON结构,需要先定义一个包裹结构体来匹配"StateMachine"键:
use serde::{Deserialize, Serialize}; #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct StateMachine { id: String, } // 用于匹配数组中每个{"StateMachine": ...}的结构 #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct StateMachineEntry { #[serde(rename = "StateMachine")] state_machine: StateMachine, } #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct Scjson { scjson: Vec<StateMachineEntry>, } // 反序列化示例 fn main() -> Result<(), serde_json::Error> { let json = r#"{ "scjson": [ { "StateMachine": { "id": "sm_1" } }, { "StateMachine": { "id": "sm_2" } } ] }"#; let data: Scjson = serde_json::from_str(json)?; println!("{:?}", data); Ok(()) }
2. 最终YAML完整解析方案
针对包含多态状态的YAML,需要用枚举来处理不同类型的状态(AtomicState、FinalState等),同时匹配各类嵌套结构:
use serde::{Deserialize, Serialize}; use serde_yaml; // 定义各类状态的结构体 #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct AtomicState { id: String, #[serde(default)] // 处理可选的transitions字段 transitions: Vec<TransitionEntry>, } #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct ParallelState { #[serde(rename = "InitialTransition")] initial_transition: InitialTransition, } #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct CompoundState { id: String, #[serde(rename = "initialTransition")] initial_transition: Transition, } #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct FinalState { id: String, #[serde(rename = "onEntry")] on_entry: String, } // 定义Transition相关结构 #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct Transition { event: String, #[serde(rename = "executable_content")] executable_content: String, } #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct TransitionEntry { #[serde(rename = "Transition")] transition: Transition, } #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct InitialTransition { // 空对象,无需字段 } // 用枚举统一所有状态类型 #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] #[serde(rename_all = "PascalCase")] pub enum State { AtomicState(AtomicState), ParallelState(ParallelState), CompoundState(CompoundState), FinalState(FinalState), } // 更新StateMachine结构体,添加states字段 #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct StateMachine { id: String, states: Vec<State>, } // 包裹StateMachine的结构体 #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct StateMachineEntry { #[serde(rename = "StateMachine")] state_machine: StateMachine, } // 顶层结构体 #[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] pub struct Scjson { scjson: Vec<StateMachineEntry>, } // YAML反序列化示例 fn main() -> Result<(), serde_yaml::Error> { let yaml = r#"scjson: - StateMachine: id: "sm_1" states: - AtomicState: id: atomic_1 - AtomicState: id: atomic_2 transitions: - Transition: { event: "E1", executable_content: "asdf" } - ParallelState: InitialTransition: { } - CompoundState: id: compound_1 initialTransition: { event: "E2", condition: "some condition" } - StateMachine: id: "sm_2" states: - FinalState: id: "asdf" onEntry: "17" "#; let data: Scjson = serde_yaml::from_str(yaml)?; println!("{:?}", data); Ok(()) }
关键说明
- 对于
{"TypeName": {...}}这种标签式结构,使用枚举+#[serde(rename_all = "PascalCase")]可以让serde自动将键名匹配到枚举变体。 - 字段命名不匹配时(比如YAML中的
initialTransition、onEntry),用#[serde(rename = "...")]手动映射。 - 可选字段(如AtomicState的transitions)添加
#[serde(default)]来处理缺失情况,默认生成空数组/默认值。
内容的提问来源于stack exchange,提问作者user3054986
相关产品推荐
相关产品推荐

