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