Rust派生宏库derive-ex的使用,简化代码生成与自动化实现

Rust派生宏库derive-ex的使用,简化代码生成与自动化实现

derive-ex是一个改进版的宏库,用于实现标准库中定义的trait。它提供了比标准派生宏更智能的特性。

与标准派生宏的区别

  • 自动生成的trait bound更智能
  • 可以手动指定trait bound
  • 可以为每个字段指定默认值
  • 可以为每个字段指定比较方法
  • 可以指定在派生Debug时忽略的字段
  • 支持派生Clone::clone_from
  • 支持派生运算符(AddAddAssignNotDeref等)

支持的trait

  • Copy
  • Clone
  • Debug
  • Default
  • Ord, PartialOrd, Eq, PartialEq, Hash
  • 运算符:
    • Add-like (Add, Sub, Mul, Shl等)
    • AddAssign-like (AddAssign, SubAssign, MulAssign, ShlAssign等)
    • Not-like (Not, Neg)
    • Deref, DerefMut

不支持的trait

以下trait不支持,因为有更合适的crate可用:

trait crate
Display, FromStr parse-display
Error thiserror

安装

在Cargo.toml中添加:

[dependencies]
derive-ex = "0.1.7"

示例

use derive_ex::derive_ex;

#[derive(Eq, PartialEq, Debug)]
#[derive_ex(Add, AddAssign, Clone, Default)]
struct X {
    #[default(10)]
    a: u32,
}
assert_eq!(X { a: 1 } + X { a: 2 }, X { a: 3 });
assert_eq!(X::default(), X { a: 10 });

#[derive(Eq, PartialEq, Debug)]
#[derive_ex(Clone, Default)]
enum Y {
    A,
    #[default]
    B,
}
assert_eq!(Y::default(), Y::B);

完整示例

use derive_ex::derive_ex;

// 定义一个结构体,自动实现多个trait
#[derive(Debug)]
#[derive_ex(Clone, Default, Add, AddAssign, PartialEq)]
struct Point {
    #[default(0.0)]  // 设置默认值为0.0
    x: f64,
    #[default(0.0)]
    y: f64,
}

// 定义一个枚举,自动实现Default和Clone
#[derive(Debug)]
#[derive_ex(Clone, Default)]
enum Shape {
    #[default]
    Circle,
    Square,
    Triangle,
}

fn main() {
    // 测试结构体的Default实现
    let p1 = Point::default();
    println!("Default point: {:?}", p1); // Point { x: 0.0, y: 0.0 }
    
    // 测试结构体的Add实现
    let p2 = Point { x: 1.0, y: 2.0 };
    let p3 = Point { x: 3.0, y: 4.0 };
    let sum = p2 + p3;
    println!("Sum of points: {:?}", sum); // Point { x: 4.0, y: 6.0 }
    
    // 测试AddAssign
    let mut p4 = Point { x: 1.0, y: 1.0 };
    p4 += Point { x: 2.0, y: 2.0 };
    println!("After +=: {:?}", p4); // Point { x: 3.0, y: 3.0 }
    
    // 测试枚举的Default实现
    let default_shape = Shape::default();
    println!("Default shape: {:?}", default_shape); // Circle
    
    // 测试Clone实现
    let cloned_shape = default_shape.clone();
    println!("Cloned shape: {:?}", cloned_shape); // Circle
}

许可证

本项目采用Apache-2.0/MIT双重许可。

贡献

除非您明确声明,否则您有意提交以包含在本工作中的任何贡献,如Apache-2.0许可证中所定义,应如上所述双重许可,没有任何附加条款或条件。


1 回复

以下是基于您提供的内容整理的Rust派生宏库derive-ex的完整示例演示:

内容中提供的示例

  1. 基本使用
use derive_ex::derive_ex;

#[derive_ex(Debug, Clone, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}
  1. 自定义派生行为
#[derive_ex(Debug, Clone)]
struct User {
    id: u64,
    #[debug(skip)]  // 在Debug输出中跳过password字段
    password: String,
    #[clone(skip)]  // 克隆时跳过session_token字段
    session_token: String,
}
  1. 为枚举自动派生
#[derive_ex(Debug, Clone, PartialEq)]
enum Status {
    Active,
    Inactive,
    Suspended(String),
}
  1. 实现自定义trait
trait Greet {
    fn greet(&self) -> String;
}

#[derive_ex(Greet)]
struct Person {
    name: String,
}

impl Greet for Person {
    fn greet(&self) -> String {
        format!("Hello, {}!", self.name)
    }
}
  1. 高级示例:组合多个派生
#[derive_ex(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]  // 与serde属性配合使用
struct ApiResponse<T> {
    status_code: u16,
    message: String,
    data: T,
    #[debug(with = "format_timestamp")]
    #[serde(skip_serializing_if = "Option::is_none")]
    timestamp: Option<u64>,
}

完整示例demo

// 完整示例:用户管理系统中的DTO和领域模型
use serde::{Serialize, Deserialize};
use derive_ex::derive_ex;

// 1. 定义自定义trait
trait DisplayName {
    fn display_name(&self) -> String;
}

// 2. 用户DTO(数据传输对象)
#[derive_ex(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct UserDTO {
    user_id: u64,
    #[debug(skip)]
    #[serde(skip_serializing)]  // 不序列化密码
    password: String,
    username: String,
    #[debug(with = "format_timestamp")]
    created_at: u64,
}

// 3. 用户领域模型
#[derive_ex(Debug, Clone, DisplayName)]
struct User {
    id: u64,
    #[debug(skip)]
    credentials: Credentials,
    profile: Profile,
}

#[derive(Debug, Clone)]
struct Credentials {
    hashed_password: String,
}

#[derive_ex(Debug, Clone, Serialize, Deserialize)]
struct Profile {
    username: String,
    email: String,
}

// 4. 实现自定义trait
impl DisplayName for User {
    fn display_name(&self) -> String {
        format!("{} ({})", self.profile.username, self.id)
    }
}

// 5. 状态枚举
#[derive_ex(Debug, Clone, PartialEq, Serialize, Deserialize)]
enum AccountStatus {
    Active,
    Inactive {
        reason: String,
        since: u64,
    },
    #[serde(rename = "banned")]
    Banned {
        #[debug(skip)]
        admin_notes: String,
        until: Option<u64>,
    },
}

// 辅助函数
fn format_timestamp(timestamp: &u64) -> String {
    format!("{}", *timestamp)  // 实际应用中可转换为可读日期
}

fn main() {
    // 使用示例
    let user_dto = UserDTO {
        user_id: 123,
        password: "secret".to_string(),
        username: "john_doe".to_string(),
        created_at: 1672531200,
    };

    let user = User {
        id: 123,
        credentials: Credentials {
            hashed_password: "hashed_secret".to_string(),
        },
        profile: Profile {
            username: "john_doe".to_string(),
            email: "john@example.com".to_string(),
        },
    };

    println!("User DTO: {:?}", user_dto);
    println!("User display name: {}", user.display_name());
}

这个完整示例展示了:

  1. 自定义trait的自动实现
  2. DTO和领域模型的不同派生配置
  3. 枚举类型的复杂派生
  4. 与serde库的配合使用
  5. 字段级别的自定义行为控制

使用时需要确保Cargo.toml中包含以下依赖:

[dependencies]
derive-ex = "0.1"
serde = { version = "1.0", features = ["derive"] }
回到顶部