5个版本
0.1.4 | 2019年3月28日 |
---|---|
0.1.3 | 2019年2月6日 |
0.1.2 | 2019年2月1日 |
0.1.1 | 2019年1月31日 |
0.1.0 | 2019年1月30日 |
#21 在 #accessor
每月22次下载
用于 detect_git_service
11KB
96 行
#[diff_enum]
Rust宏
这是一个小型Rust库,提供了一个属性宏 #[diff_enum::common_fields]
,通过差异帮助定义 enum
变体。当需要处理几乎相同但部分不同的数据时非常有用。
通过属性宏,可以分别定义所有变体之间的公共字段和每个变体的不同字段。公共字段只定义一次。此外,还会自动定义公共字段的访问器方法。
例如,
extern crate diff_enum;
use diff_enum::common_fields;
#[common_fields {
user: String,
name: String,
stars: u32,
issues: u32,
}]
#[derive(Debug)]
enum RemoteRepo {
GitHub {
language: String,
pull_requests: u32,
}
GitLab {
merge_requests: u32,
}
}
被展开为
#[derive(Debug)]
enum RemoteRepo {
GitHub {
language: String,
pull_requests: u32,
user: String,
name: String,
stars: u32,
issues: u32,
}
GitLab {
merge_requests: u32,
user: String,
name: String,
stars: u32,
issues: u32,
}
}
此外,还会为公共字段定义访问器函数。例如,
let repo = RemoteRepo::GitHub {
user: "rust-lang".to_string(),
name: "rust".to_string(),
language: "rust".to_string(),
issues: 4536,
pull_requests: 129,
stars: 33679,
};
println!("User: {}", repo.user());
替代方案
如果没有这个crate,通常会将数据分为具有公共字段的结构体和表示差异的枚举变体。
对于上面的 RemoteRepo
例子,
enum RemoteRepoKind {
GitHub {
language: String,
pull_requests: u32,
}
GitLab {
merge_requests: u32,
}
}
struct RemoteRepo {
user: String,
name: String,
stars: u32,
issues: u32,
kind: RemoteRepoKind,
}
这个解决方案存在以下问题
- 字段被分成两部分,这是由于Rust枚举的原因。本质上,GitHub仓库的issue数量和pull request数量都是属性。作为自然的数据结构,它们应该位于相同的扁平结构体中。
- 为内部枚举命名很困难。在这里我使用了'Kind'来区分部分。但这是否合适?'Kind'是一个过于通用的名称,含义较弱。弱名称来自数据结构的尴尬。
安装
请将此crate添加到项目的Cargo.toml
依赖中。
[dependencies]
diff-enum = "0.1"
用法
首先,请加载此crate。
extern crate diff_enum;
use diff_enum::common_fields;
并使用#[common_fields]
属性宏为您的枚举定义。
#[common_fields {
common fields here...
}]
enum ...
或者如果您喜欢,可以使用完全限定名称
#[diff_enum::common_fields {
common fields here...
}]
enum ...
任何属性和注释都可以像普通的enum
字段一样放置到公共字段中。
定义了与公共字段相对应的访问器方法。它是一个非常有用的辅助工具,可以在不使用模式匹配的情况下访问公共字段。
例如,
#[common_fields { i: i32 }]
enum E { A, B{ b: bool } }
如下生成对i
的访问器方法
impl E {
fn i(&self) -> &i32 {
match self {
E::A{ref i, ..} => i,
E::B{ref i, ..} => i,
}
}
}
在以下情况下,属性宏会导致编译错误。
- 当没有放置公共字段时
- 当属性参数中的字段不是
field: type
的形式时 - 当
#[common_fields {...}]
设置为除了enum
定义之外的内容时 - 当在
enum
定义中使用元组样式的枚举变体时
许可证
在MIT许可证下分发。
依赖关系
约2MB
约46K SLoC