Rust枚举与字符串转换库sea-strum的使用,高效实现枚举与字符串间的双向转换

Rust枚举与字符串转换库strum的使用,高效实现枚举与字符串间的双向转换

Strum是一组用于在Rust中更轻松处理枚举和字符串的宏和特性集合。

兼容性

Strum目前支持Rust版本>=1.32.0。该项目目标是支持至少2年的Rust版本。

在项目中包含Strum

在Cargo.toml中添加以下依赖:

[dependencies]
strum = "0.23"
strum_macros = "0.23"

# 也可以使用"derive"特性,直接从"strum"导入宏
# strum = { version = "0.23", features = ["derive"] }

Strum宏

Strum实现了以下宏:

描述
EnumString 根据名称将字符串转换为枚举变体
Display 将枚举变体转换为字符串
FromRepr 从整数转换为枚举
AsRefStr 为MyEnum实现AsRef<str>
IntoStaticStr 为枚举实现From<MyEnum> for &'static str
EnumVariantNames 添加关联的VARIANTS常量,是判别名称的数组
EnumIter 创建迭代枚举变体的新类型
EnumProperty 向枚举变体添加自定义属性
EnumMessage 向枚举变体添加详细消息
EnumDiscriminants 生成仅包含判别名称的新类型
EnumCount 添加等于变体数量的常量usize

完整示例代码

以下是一个完整的示例,展示如何使用strum实现枚举与字符串的双向转换:

use strum_macros::{Display, EnumString};

#[derive(Debug, Display, EnumString, PartialEq)]
enum Color {
    #[strum(serialize = "red", serialize = "r")]
    Red,
    #[strum(serialize = "green", serialize = "g")]
    Green,
    #[strum(serialize = "blue", serialize = "b")]
    Blue,
}

fn main() {
    // 枚举转字符串
    let red_str = Color::Red.to_string();
    println!("Red as string: {}", red_str); // 输出: red
    
    // 字符串转枚举
    let color: Color = "green".parse().unwrap();
    assert_eq!(color, Color::Green);
    
    // 使用替代名称
    let color: Color = "b".parse().unwrap();
    assert_eq!(color, Color::Blue);
}

这个示例展示了:

  1. 使用Display特性将枚举转换为字符串
  2. 使用EnumString特性将字符串解析为枚举
  3. 为每个枚举变体定义多个字符串表示形式

扩展示例代码

// 导入需要的宏
use strum_macros::{Display, EnumString, EnumIter, EnumCount};

#[derive(Debug, Display, EnumString, EnumIter, EnumCount, PartialEq)]
enum HttpStatus {
    #[strum(serialize = "200 OK", serialize = "ok")]
    Ok,
    #[strum(serialize = "404 Not Found")]
    NotFound,
    #[strum(serialize = "500 Internal Server Error")]
    InternalServerError,
}

fn main() {
    // 1. 枚举转字符串
    println!("Status: {}", HttpStatus::Ok); // 输出: 200 OK
    
    // 2. 字符串转枚举
    let status: HttpStatus = "404 Not Found".parse().unwrap();
    assert_eq!(status, HttpStatus::NotFound);
    
    // 3. 使用EnumIter迭代所有变体
    println!("\nAll HTTP status variants:");
    for variant in HttpStatus::iter() {
        println!("- {:?}", variant);
    }
    
    // 4. 使用EnumCount获取变体数量
    println!("\nTotal variants: {}", HttpStatus::COUNT);
    
    // 5. 使用替代名称解析
    let status: HttpStatus = "ok".parse().unwrap();
    assert_eq!(status, HttpStatus::Ok);
}

调试

要查看生成的代码,可以在编译前设置STRUM_DEBUG环境变量:

  • STRUM_DEBUG=1 将显示所有类型的生成代码
  • STRUM_DEBUG=YourType 将仅显示特定类型的生成代码

名称由来

Strum是STRING enUM的缩写,因为它是一个通过字符串增强枚举信息的库。Strumming也是一种非常随意的动作,很像编写Rust代码。


1 回复

Rust枚举与字符串转换库strum的使用指南

strum是一个强大的Rust库,专门用于简化枚举(enum)与字符串之间的双向转换操作。它通过过程宏提供了一系列特性,可以高效地实现枚举值与字符串表示之间的相互转换。

主要特性

  1. 自动实现ToString/FromStr trait
  2. 支持枚举变体到字符串的各种命名风格转换
  3. 支持枚举的序列化/反序列化
  4. 提供枚举变体的迭代功能

基本用法

首先在Cargo.toml中添加依赖:

[dependencies]
strum = "0.25"
strum_macros = "0.25"

示例1:基本字符串转换

use strum_macros::{Display, EnumString};

#[derive(Debug, Display, EnumString, PartialEq)]
enum Color {
    Red,
    Blue,
    Green,
    #[strum(serialize = "Yellow", serialize = "Golden")]
    Yellow,
}

fn main() {
    // 枚举转字符串
    assert_eq!("Red", Color::Red.to_string());
    assert_eq!("Yellow", Color::Yellow.to_string());
    
    // 字符串转枚举
    assert_eq!(Color::Red, "Red".parse().unwrap());
    assert_eq!(Color::Yellow, "Golden".parse().unwrap());
}

示例2:自定义字符串表示

use strum_macros::{Display, EnumString};

#[derive(Debug, Display, EnumString)]
enum HttpStatus {
    #[strum(serialize = "200 OK")]
    Ok,
    #[strum(serialize = "404 Not Found")]
    NotFound,
    #[strum(serialize = "500 Internal Server Error")]
    InternalServerError,
}

fn main() {
    println!("{}", HttpStatus::Ok); // 输出 "200 OK"
    let status: HttpStatus = "404 Not Found".parse().unwrap();
    println!("{:?}", status); // 输出 "NotFound"
}

示例3:自动命名风格转换

use strum_macros::{Display, EnumString};

#[derive(Debug, Display, EnumString)]
#[strum(serialize_all = "snake_case")]
enum ProgrammingLanguage {
    Rust,
    JavaScript,
    TypeScript,
    CPlusPlus,
}

fn main() {
    assert_eq!("rust", ProgrammingLanguage::Rust.to_string());
    assert_eq!(ProgrammingLanguage::JavaScript, "javascript".parse().unwrap());
}

高级用法

枚举变体迭代

use strum_macros::{Display, EnumIter};
use strum::IntoEnumIterator;

#[derive(Debug, Display, EnumIter)]
enum Direction {
    North,
    South,
    East,
    West,
}

fn main() {
    for direction in Direction::iter() {
        println!("{}", direction);
    }
}

配合Serde使用

use strum_macros::{Display, EnumString, Serialize, Deserialize};
use serde::{Serialize, Deserialize};

#[derive(Debug, Display, EnumString, Serialize, Deserialize)]
enum Fruit {
    Apple,
    Banana,
    Orange,
}

fn main() {
    let fruit = Fruit::Apple;
    let json = serde_json::to_string(&fruit).unwrap();
    println!("{}", json); // 输出 ""Apple""
    
    let fruit: Fruit = serde_json::from_str("\"Banana\"").unwrap();
    assert_eq!(fruit, Fruit::Banana);
}

常见宏说明

  1. Display - 自动派生ToString trait
  2. EnumString - 自动派生FromStr trait
  3. EnumIter - 为枚举提供迭代功能
  4. IntoStaticStr - 将枚举转换为&'static str
  5. EnumVariantNames - 获取所有变体名称的数组

完整示例代码

下面是一个整合了strum主要功能的完整示例:

// 引入必要的宏和trait
use strum_macros::{Display, EnumString, EnumIter, EnumVariantNames};
use strum::IntoEnumIterator;
use serde::{Serialize, Deserialize};

// 定义一个使用多种strum特性的枚举
#[derive(Debug, Display, EnumString, EnumIter, EnumVariantNames, PartialEq, Serialize, Deserialize)]
#[strum(serialize_all = "kebab-case")]
enum Animal {
    #[strum(serialize = "Dog", serialize = "Canine")]
    Dog,
    Cat,
    #[strum(serialize = "Elephant", serialize = "BigAnimal")]
    Elephant,
    #[strum(disabled)]
    HiddenAnimal,
}

fn main() {
    // 1. 测试Display特性 - 枚举转字符串
    println!("\n--- 枚举转字符串 ---");
    println!("Dog: {}", Animal::Dog.to_string()); // 输出 "dog"
    println!("Elephant: {}", Animal::Elephant.to_string()); // 输出 "elephant"
    
    // 2. 测试EnumString特性 - 字符串转枚举
    println!("\n--- 字符串转枚举 ---");
    let dog: Animal = "Dog".parse().unwrap();
    println!("解析Dog: {:?}", dog);
    let elephant: Animal = "BigAnimal".parse().unwrap();
    println!("解析BigAnimal: {:?}", elephant);
    
    // 3. 测试EnumIter特性 - 枚举迭代
    println!("\n--- 枚举迭代 ---");
    for animal in Animal::iter() {
        println!("迭代: {}", animal);
    }
    
    // 4. 测试EnumVariantNames特性 - 获取所有变体名称
    println!("\n--- 枚举变体名称 ---");
    println!("所有变体: {:?}", Animal::VARIANTS);
    
    // 5. 测试与Serde的集成
    println!("\n--- Serde序列化/反序列化 ---");
    let animal = Animal::Cat;
    let json = serde_json::to_string(&animal).unwrap();
    println!("序列化: {}", json);
    let animal: Animal = serde_json::from_str("\"elephant\"").unwrap();
    println!("反序列化: {:?}", animal);
}

这个完整示例展示了strum库的核心功能:

  1. 枚举与字符串之间的双向转换
  2. 多种字符串表示形式支持
  3. 枚举迭代功能
  4. 获取枚举变体名称
  5. 与Serde的集成使用

strum库极大地简化了Rust中枚举与字符串之间的转换工作,是处理这类需求的理想选择。

回到顶部