7 个版本 (破坏性更新)

0.7.0 2023 年 11 月 27 日
0.6.0 2023 年 11 月 17 日
0.5.0 2023 年 11 月 16 日
0.4.0 2023 年 11 月 13 日
0.1.0 2023 年 11 月 13 日

734Rust 模式

Download history 2240/week @ 2024-03-13 795/week @ 2024-03-20 1118/week @ 2024-03-27 850/week @ 2024-04-03 1212/week @ 2024-04-10 704/week @ 2024-04-17 627/week @ 2024-04-24 497/week @ 2024-05-01 458/week @ 2024-05-08 531/week @ 2024-05-15 571/week @ 2024-05-22 291/week @ 2024-05-29 316/week @ 2024-06-05 1001/week @ 2024-06-12 864/week @ 2024-06-19 312/week @ 2024-06-26

每月 2,520 次下载

MIT 许可证

25KB
357

枚举公共字段

概述

用于生成枚举中公共字段获取器/设置器的宏。也就是说,如果你的枚举的每个变体都有一些字段,你就可以通过 field() 和 field_mut() 访问器分别访问它。

例如,如果你有一个类型为 String 的公共字段 key,你可以使用宏如下

#[derive(EnumCommonFields)]
#[common_field(mut key: String)]
enum MyEnum {
    // Some variants
}

并拥有方法 .key().key_mut(),分别返回 &String&mut String。如果你不想创建 .key_mut() 访问器,你可以在声明中省略 mut,如下所示

#[derive(EnumCommonFields)]
#[common_field(key: String)]
enum MyEnum {
    // Some variants
}

背景

枚举变体具有公共字段的情况相当普遍,如下所示

struct CreateRequest {
    id: String,
    // other fields
}
struct UpdateRequest {
    id: String,
    // other fields
}
enum Request {
    Create(CreateRequest),
    Update(UpdateRequest),
}

但是,如果你有一个枚举实例,访问公共字段会很麻烦

fn handle(req: Request) {
    let id = match req { 
        Update(r) => r.id,
        Create(r) => r.id,
    };
    // ...
}

在这种情况下,常见的建议是将公共字段提取到封装的结构体中

struct CreateRequest {
    // fields
}
struct UpdateRequest {
    // fields
}
enum RequestKind {
    Create(CreateRequest),
    Update(UpdateRequest),
}
struct Request {
    id: String,
    req: RequestKind,
}

但这会使需要使用公共字段的具体处理函数复杂化。例如

fn create_handler(
    id: String, // need to get id as a param by itself 
    req: CreateRequest
) {
    // ...
}

此宏通过自动生成公共字段的访问器方法来解决此问题。例如

struct CreateRequest {
    id: String,
    // other fields
}
struct UpdateRequest {
    id: String,
    // other fields
}

#[derive(EnumCommonFields)]
#[common_field(id: String)]
enum Request {
    Create(CreateRequest),
    Update(UpdateRequest),
}
fn handle(req: Request) {
    let id = req.id();
    // ...
}

生成的访问器与以下等价

impl Request {
    fn id(&self) -> &String {
        match self {
            Update(r) => r.id,
            Create(r) => r.id,
        }
    }
}

安装

将以下内容添加到你的 Cargo.toml

enum_common_fields = "0.7.0"

使用方法

有关完整参考,请参阅 文档

缺失的功能

有一些功能是可以实现的,但我认为添加它们的努力不值得。因此,如果您是少数真正需要其中之一的人,请在 issues 中随意打扰我。

批量重命名访问器

我在谈论既重命名访问器的 'base' 字段名称(因此对于字段 identifier 将生成 id()id_mut()),又更改访问器名称 'template'(因此所有不可变访问器都将为 get_field() 而不是仅仅是 field())。这是可能的,但我相信大多数人会完全接受我的约定。

复合所有者访问器

目前,所有者访问器的功能相当有限。如果您想获取枚举实例中多个公共字段的拥有权,则需要回退到使用具有许多相同分支的 match。理论上我可以生成一个 into_common() 方法,该方法将返回所有具有所有者访问器的字段。问题是这个理论方法返回的类型。为所有公共字段生成结构体似乎太多,但如果许多字段具有相同类型,仅返回一个元组可能会非常令人困惑。

具有一个注解的访问器的奇怪组合

我真的不相信有人需要经常生成仅拥有和可变访问器的字段,以至于要讨论它。

转换

目前,宏执行的转换仅限于从 DerefDerefMut 特性。例如,您可以使用 str 作为 String 字段 ref 访问器的类型。这样,访问器将返回 &str&mut str。但它不会调用 into() 或其他任何转换。

依赖关系

~295–750KB
~18K SLoC