2个版本
0.1.1 | 2019年7月7日 |
---|---|
0.1.0 | 2019年6月25日 |
#1189 in 过程宏
16KB
235 行
enumerate
这个crate提供了一个过程宏,给定一个特性和其实现者,生成一个枚举,然后可以用来替代特例对象,避免动态调度。这个概念基于enum_dispatch crate,但这个实现更专注于给用户提供一个更加简洁的API,需要的样板代码更少。
用法
任何特性能通过#[enumerate(<implementers>)]
进行标注来生成相应的枚举。
示例
以下示例展示了如何使用宏从一个特性和两个实现者生成枚举。
#[enumerate(Talker, Shouter)]
pub trait SayMessage {
fn say_message(&self);
}
pub struct Talker {
message: String
}
impl SayMessage for Talker {
fn say_message(&self) {
println!("{}", self.message);
}
}
pub struct Shouter {
message: String,
repetitions: i32
}
impl SayMessage for Shouter {
fn say_message(&self) {
for _ in 0..self.repetitions {
println!("{}", self.message.to_uppercase());
}
}
}
这将生成与特性同名的枚举(在这个例子中是SayMessage
)。它将具有Talker
和Shouter
这两个变体。因为你显然不能在同一个模块内有相同标识符的两个类型,所以enumerate
会将枚举放入一个子模块中。这些子模块的名称是通过将标注的特性的名称转换为snake_case并附加_enm
来生成的。所以上面的例子将创建一个名为say_message_enm
的模块。
自定义名称
还可以为枚举及其变体指定自定义名称。指定枚举的名称是通过将宏的第一个参数添加为<name>:
来完成的。可以通过使用语法<implementer> as <name>
指定变体的自定义名称。所有这些都在下面的示例中得到了展示。
#[enumerate(InterestingName: ImplementerOne as One, ImplementerTwo as Two)]
pub trait BoringName { /* ... */ }
pub struct ImplementerOne;
impl BoringName for ImplementerOne { /* ... */ }
pub struct ImplementerTwo;
impl BoringName for ImplementerTwo { /* ... */ }
这将生成一个名为 InterestingName
的枚举,其变体为 One
和 Two
。由于枚举和特质之间现在没有命名冲突,因此不需要创建额外的模块,枚举将放置在特质的同一模块中。
实例化
enumerate
自动为每个变体生成 From<T>
的实现。这意味着您可以使用 <enum>::from(<instance>)
以及 <instance>.into()
从实现注解特质的实例获取枚举的实例。以下是一个示例。
let instance = Implementer::new();
let enum_instance = Enum::from(instance);
let alternative = Implementer::new();
let alt_enum_instance: Enum = alternative.into();
enum_instance.trait_method();
alt_enum_instance.trait_method();
关联函数
您不能调用由此宏生成的枚举的关联函数。枚举的生成将正常工作,但在枚举上调用任何关联函数将导致 panic。
依赖项
~2MB
~46K SLoC