Rust枚举变体检测库derive_is_enum_variant的使用:通过过程宏自动生成enum变体验证方法

Rust枚举变体检测库derive_is_enum_variant的使用:通过过程宏自动生成enum变体验证方法

derive_is_enum_variant

不再需要手动为你的enum编写pub is_whatever(&self) -> bool方法了!只需使用#[derive(is_enum_variant)]宏即可自动生成这些方法。

使用方法

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

[dependencies]
derive_is_enum_variant = "0.1.1"  # 请使用最新版本

然后在枚举定义上使用派生宏:

#[macro_use]
extern crate derive_is_enum_variant;

#[derive(is_enum_variant)]
pub enum Animal {
    Dog,
    Cat,
}

fn main() {
    let animal = Animal::Dog;
    
    // 自动生成的方法
    assert!(animal.is_dog());
    assert!(!animal.is_cat());
}

自定义方法名称

可以为枚举变体指定自定义的检测方法名称:

#[derive(is_enum_variant)]
pub enum Animal {
    #[is_enum_variant(name = "is_doggy")]
    Dog,
    Cat,
}

let animal = Animal::Dog;
assert!(animal.is_doggy());  // 使用自定义的方法名

跳过特定变体

对于不需要生成检测方法的变体,可以使用skip属性:

#[derive(is_enum_variant)]
pub enum Error {
    Io(std::io::Error),
    #[is_enum_variant(skip)]
    InternalError,
}

完整示例代码

// 1. 在Cargo.toml中添加依赖
// [dependencies]
// derive_is_enum_variant = "0.1.1"

// 2. 实际使用示例
#[macro_use]
extern crate derive_is_enum_variant;

#[derive(Debug, is_enum_variant)]
enum NetworkStatus {
    // 默认生成is_connected方法
    Connected,
    
    // 自定义方法名
    #[is_enum_variant(name = "is_disconnected_status")]
    Disconnected,
    
    // 带数据的变体
    Error(String),
    
    // 跳过生成方法
    #[is_enum_variant(skip)]
    Unknown,
}

fn main() {
    let connected = NetworkStatus::Connected;
    let disconnected = NetworkStatus::Disconnected;
    let error = NetworkStatus::Error("Timeout".to_string());
    let unknown = NetworkStatus::Unknown;
    
    // 测试生成的方法
    assert!(connected.is_connected());
    assert!(!connected.is_disconnected_status());
    assert!(!connected.is_error());
    
    assert!(disconnected.is_disconnected_status());
    
    assert!(error.is_error());
    assert_eq!(error.is_connected(), false);
    
    // 跳过的变体不会有对应方法
    // unknown.is_unknown(); // 这会编译错误
}

许可证

此库采用以下许可证之一:

  • Apache License, Version 2.0
  • MIT license

可根据需要选择使用。


1 回复

Rust枚举变体检测库derive_is_enum_variant使用指南

derive_is_enum_variant是一个方便的Rust过程宏库,它能够自动为枚举类型生成检测变体的方法,避免了手动编写大量match语句或if let表达式的麻烦。

安装

Cargo.toml中添加依赖:

[dependencies]
derive_is_enum_variant = "0.1"

基本用法

使用#[derive(IsEnumVariant)]宏来自动生成is_前缀的变体检测方法:

use derive_is_enum_variant::IsEnumVariant;

#[derive(IsEnumVariant)]
enum MyEnum {
    VariantA,
    VariantB(i32),
    VariantC { x: f64, y: f64 },
}

这将自动生成以下方法:

  • is_variant_a()
  • is_variant_b()
  • is_variant_c()

示例代码

use derive_is_enum_variant::IsEnumVariant;

#[derive(Debug, IsEnumVariant)]
enum NetworkEvent {
    Connect,
    Message(String),
    Disconnect { reason: String },
}

fn handle_event(event: NetworkEvent) {
    if event.is_connect() {
        println!("Connection established");
    } else if event.is_message() {
        println!("Received message");
    } else if event.is_disconnect() {
        println!("Disconnected: {:?}", event);
    }
}

fn main() {
    let events = vec![
        NetworkEvent::Connect,
        NetworkEvent::Message("Hello".to_string()),
        NetworkEvent::Disconnect { reason: "Timeout".to_string() },
    ];

    for event in events {
        handle_event(event);
    }
}

高级特性

自定义方法名前缀

默认生成的方法以is_为前缀,但你可以自定义:

#[derive(IsEnumVariant)]
#[is_enum_variant(prefix = "check_")]
enum CustomEnum {
    First,
    Second,
}
// 生成 check_first() 和 check_second() 方法

忽略特定变体

可以忽略某些变体不生成检测方法:

#[derive(IsEnumVariant)]
#[is_enum_variant(skip(VariantB, VariantC))]
enum SkipEnum {
    VariantA,
    VariantB,
    VariantC,
}
// 只生成 is_variant_a() 方法

完整示例代码

// 导入必要的库
use derive_is_enum_variant::IsEnumVariant;
use std::fmt;

// 定义一个带有派生宏的枚举
#[derive(Debug, IsEnumVariant)]
enum UserAction {
    Login { username: String, password: String },
    Logout,
    SendMessage { recipient: String, content: String },
    ChangePassword(String),
}

// 实现Display trait以便更好地打印
impl fmt::Display for UserAction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            UserAction::Login { username, password: _ } => 
                write!(f, "Login attempt by {}", username),
            UserAction::Logout => 
                write!(f, "User logged out"),
            UserAction::SendMessage { recipient, content } => 
                write!(f, "Message to {}: {}", recipient, content),
            UserAction::ChangePassword(_) => 
                write!(f, "Password change requested"),
        }
    }
}

fn process_action(action: UserAction) {
    // 使用自动生成的检测方法
    if action.is_login() {
        println!("处理登录: {}", action);
    } else if action.is_logout() {
        println!("处理登出: {}", action);
    } else if action.is_send_message() {
        println!("处理消息发送: {}", action);
    } else if action.is_change_password() {
        println!("处理密码修改: {}", action);
    }
}

fn main() {
    // 创建各种用户操作
    let actions = vec![
        UserAction::Login { 
            username: "alice".to_string(), 
            password: "secret".to_string() 
        },
        UserAction::Logout,
        UserAction::SendMessage { 
            recipient: "bob".to_string(), 
            content: "Hello!".to_string() 
        },
        UserAction::ChangePassword("newpassword".to_string()),
    ];

    // 处理每个操作
    for action in actions {
        process_action(action);
    }
}

适用场景

  1. 当需要频繁检查枚举当前是哪个变体时
  2. 当枚举有很多变体,手动实现检测方法很繁琐时
  3. 需要更简洁的代码表达变体检查逻辑时

注意事项

  1. 生成的检测方法返回bool类型
  2. 方法名由变体名转换而来,遵循Rust的命名约定(小写下划线风格)
  3. 对于元组变体或结构体变体,检测方法只检查变体类型,不检查内部值

这个库可以显著简化枚举变体的检测代码,使代码更加清晰易读。

回到顶部