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

Rust中如何实现嵌套枚举与字符串的相互转换?

Rust嵌套枚举与字符串双向转换的解决方案

方法一:基于Serde自定义序列化/反序列化

利用Serde的序列化框架,自定义逻辑生成和解析目标格式的字符串,无需手动维护大量match分支。

首先添加依赖:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

实现代码:

use serde::{Serialize, Deserialize, Serializer, Deserializer};

#[derive(Debug, Clone, PartialEq)]
pub enum CharacterCreationAction {
    Open,
}

#[derive(Debug, Clone, PartialEq)]
pub enum InteractionCode {
    MenuCharacterCreation { action: CharacterCreationAction },
}

// 子枚举的序列化与反序列化
impl Serialize for CharacterCreationAction {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let s = match self {
            CharacterCreationAction::Open => "Open",
        };
        serializer.serialize_str(s)
    }
}

impl<'de> Deserialize<'de> for CharacterCreationAction {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        match s.as_str() {
            "Open" => Ok(CharacterCreationAction::Open),
            _ => Err(serde::de::Error::custom(format!("未知操作: {}", s))),
        }
    }
}

// 父枚举的自定义序列化,生成"前缀_子枚举值"格式
impl Serialize for InteractionCode {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let s = match self {
            InteractionCode::MenuCharacterCreation { action } => {
                // 序列化子枚举后去掉引号,拼接成目标格式
                format!("MenuCharacterCreation_{}", serde_json::to_string(action).unwrap().trim_matches('"'))
            }
        };
        serializer.serialize_str(&s)
    }
}

// 父枚举的反序列化,拆分字符串后解析子枚举
impl<'de> Deserialize<'de> for InteractionCode {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        let parts: Vec<&str> = s.split('_').collect();
        if parts.len() != 2 {
            return Err(serde::de::Error::custom(format!("无效格式: {}", s)));
        }

        match parts[0] {
            "MenuCharacterCreation" => {
                let action = serde_json::from_str(&format!("\"{}\"", parts[1]))
                    .map_err(serde::de::Error::custom)?;
                Ok(InteractionCode::MenuCharacterCreation { action })
            }
            _ => Err(serde::de::Error::custom(format!("未知交互类型: {}", parts[0]))),
        }
    }
}

// 测试示例
fn main() {
    let code = InteractionCode::MenuCharacterCreation { action: CharacterCreationAction::Open };
    let serialized = serde_json::to_string(&code).unwrap();
    println!("序列化结果: {}", serialized); // 输出 "MenuCharacterCreation_Open"
    
    let parsed: InteractionCode = serde_json::from_str(&serialized).unwrap();
    assert_eq!(parsed, code);
}

方法二:使用nested-enum-derive crate

该 crate 专为嵌套枚举设计,可自动生成字符串转换方法,省去手动编写代码的麻烦。

添加依赖:

[dependencies]
nested-enum-derive = "0.1"

实现代码(将结构体变体改为元组变体以适配crate):

use nested_enum_derive::NestedEnum;

#[derive(Debug, Clone, PartialEq, NestedEnum)]
pub enum CharacterCreationAction {
    Open,
}

#[derive(Debug, Clone, PartialEq, NestedEnum)]
pub enum InteractionCode {
    MenuCharacterCreation(CharacterCreationAction),
}

// 测试示例
fn main() {
    let code = InteractionCode::MenuCharacterCreation(CharacterCreationAction::Open);
    let serialized = code.as_str();
    assert_eq!(serialized, "MenuCharacterCreation_Open");
    
    let parsed = InteractionCode::from_str(serialized).unwrap();
    assert_eq!(parsed, code);
}

方法三:手动封装转换Trait(轻量方案)

如果不想引入额外依赖,可定义通用Trait并为每个枚举实现,逻辑清晰且适合小型项目。

pub trait EnumToString {
    fn to_string(&self) -> String;
}

pub trait StringToEnum: Sized {
    fn from_string(s: &str) -> Option<Self>;
}

impl EnumToString for CharacterCreationAction {
    fn to_string(&self) -> String {
        match self {
            CharacterCreationAction::Open => "Open".to_string(),
        }
    }
}

impl StringToEnum for CharacterCreationAction {
    fn from_string(s: &str) -> Option<Self> {
        match s {
            "Open" => Some(Self::Open),
            _ => None,
        }
    }
}

impl EnumToString for InteractionCode {
    fn to_string(&self) -> String {
        match self {
            InteractionCode::MenuCharacterCreation { action } => {
                format!("MenuCharacterCreation_{}", action.to_string())
            }
        }
    }
}

impl StringToEnum for InteractionCode {
    fn from_string(s: &str) -> Option<Self> {
        let parts: Vec<&str> = s.split('_').collect();
        if parts.len() != 2 {
            return None;
        }

        match parts[0] {
            "MenuCharacterCreation" => {
                CharacterCreationAction::from_string(parts[1]).map(|action| {
                    InteractionCode::MenuCharacterCreation { action }
                })
            }
            _ => None,
        }
    }
}

// 测试示例
fn main() {
    let code = InteractionCode::MenuCharacterCreation { action: CharacterCreationAction::Open };
    let serialized = code.to_string();
    assert_eq!(serialized, "MenuCharacterCreation_Open");
    
    let parsed = InteractionCode::from_string(&serialized).unwrap();
    assert_eq!(parsed, code);
}

内容的提问来源于stack exchange,提问作者Iron_Teapot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 03:00:07