业务背景
今天在公司见到这么一段代码(已去除业务属性):
rust
use std::fmt::Display;
enum Job {
Pre,
Post,
}
impl Display for Job {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Job::Pre => write!(f, "Pre Job"),
Job::Post => write!(f, "Post Job"),
}
}
}
pub fn main() {
println!("This is {}.", Job::Pre);
println!("This is {}.", Job::Post);
}
抽取出的代码功能很简单,其中定义了Pre(前置)和Post(后置)两种Job(工作)枚举,为了在日志打印信息,对其实现了std::fmt::Display
特征。这里用main
函数模拟打印日志的过程,打印结果为:
shell
This is Pre Job.
This is Post Job.
这段代码功能上没有问题,但也有较明显的缺点:
- 代码不够简洁。
- 考虑扩展性,比如再加一种Job类型或将打印内容统一改成"Jobs",当前的写法都需要持续的增加修改代码。
为了解决这个问题,我们开始无情重构!
无情重构 - strum/strum_macros
我们可以通过strum来解决这个问题。
strum是一个增强rust中enum
和String
的,由macro
和trait
组成的集合。当前版本为@0.27.1,其实现了如下macro
:
Macro | Description |
---|---|
EnumString | Converts strings to enum variants based on their name. |
Display | Converts enum variants to strings |
FromRepr | Convert from an integer to an enum. |
AsRefStr | Implement AsRef<str> for MyEnum |
IntoStaticStr | Implements From<MyEnum> for &'static str on an enum |
EnumIter | Creates a new type that iterates of the variants of an enum. |
EnumProperty | Add custom properties to enum variants. |
EnumMessage | Add a verbose message to an enum variant. |
EnumDiscriminants | Generate a new type with only the discriminant names. |
EnumCount | Add a constant usize equal to the number of variants. |
VariantArray | Adds an associated VARIANTS constant which is an array of all enum discriminants |
VariantNames | Adds an associated VARIANTS constant which is an array of discriminant names |
EnumTable | Experimental, creates a new type that stores an item of a specified type for each variant of the enum. |
在这里,我们需要使用Display
这个macro
。在项目中添加依赖:
shell
cargo add strum -F derive
cargo add strum_macros
通过如下代码实现原本功能:
rust
// use std::fmt::Display;
use strum::Display;
#[derive(Display)]
enum Job {
#[strum(serialize = "Pre Job")]
Pre,
#[strum(serialize = "Post Job")]
Post,
}
// impl Display for Job {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// match self {
// Job::Pre => write!(f, "Pre Job"),
// Job::Post => write!(f, "Post Job"),
// }
// }
// }
pub fn main() {
println!("This is {}.", Job::Pre);
println!("This is {}.", Job::Post);
}
无情重构 - derive_more
我们也可以通过derive_more来解决这个问题。
derive_more提供像Add
, Not
, From
or Display
这些trait
的派生宏实现。当前版本为@2.0.1。
在项目中添加依赖:
shell
cargo add derive_more -F display
通过如下代码实现原本功能:
rust
// use std::fmt::Display;
use derive_more::Display;
#[derive(Display)]
#[display("{_variant} Job")]
enum Job {
Pre,
Post,
}
// impl Display for Job {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// match self {
// Job::Pre => write!(f, "Pre Job"),
// Job::Post => write!(f, "Post Job"),
// }
// }
// }
pub fn main() {
println!("This is {}.", Job::Pre);
println!("This is {}.", Job::Post);
}