4个版本 (2个重大更新)
0.3.1 | 2021年1月7日 |
---|---|
0.3.0 | 2020年11月24日 |
0.2.0 | 2020年4月30日 |
0.1.2 |
|
0.1.1 | 2020年4月28日 |
在#密封中排名第8
18KB
239 行
proxy-enum
使用代理枚举模拟动态分派和"密封类",将所有方法调用推迟到其变体上。
简介
在Rust中,动态分派是通过特质对象(dyn Trait
)实现的。它们使我们能够实现运行时多态性,一种表示类型实现特定特质而忽略其实际实现的方法。
let animal: &dyn Animal = random_animal();
animal.feed(); // may print "mew", "growl" or "squeak"
然而,特质对象也有缺点:从特质对象(向下转换)获取具体实现是痛苦的。(见 std::any::Any)
如果你知道只有有限数量的实现可以与之交互,那么enum
可能更适合表示这种关系
enum Animal {
Cat(Cat),
Lion(Lion),
Mouse(Mouse)
}
match random_animal() {
Animal::Cat(cat) => cat.feed(),
Animal::Lion(lion) => lion.feed(),
Animal::Mouse(mouse) => mouse.feed()
}
一些语言为此类类型提供了特殊支持,例如Kotlin的所谓"密封类"。
然而,Rust 并不 支持。
proxy-enum
通过过程宏简化了此类类型的处理。
用法
#[proxy_enum::proxy(Animal)]
mod proxy {
enum Animal {
Cat(Cat),
Lion(Lion),
Mouse(Mouse)
}
impl Animal {
#[implement]
fn feed(&self) {}
}
}
这将扩展为
mod proxy {
enum Animal {
Cat(Cat),
Lion(Lion),
Mouse(Mouse)
}
impl Animal {
fn feed(&self) {
match self {
Animal::Cat(cat) => cat.feed(),
Animal::Lion(lion) => lion.feed(),
Animal::Mouse(mouse) => mouse.feed()
}
}
}
impl From<Cat> for Animal { /* ... */ }
impl From<Lion> for Animal { /* ... */ }
impl From<Mouse> for Animal { /* ... */ }
}
然而,只有当Cat
、Lion
和Mouse
都具有名为feed
的方法时,这段代码才能编译。由于Rust有特质来表达通用功能,因此也可以生成特质的实现
#[proxy_enum::proxy(Animal)]
mod proxy {
enum Animal {
Cat(Cat),
Lion(Lion),
Mouse(Mouse)
}
trait Eat {
fn feed(&self);
}
#[implement]
impl Eat for Animal {}
}
由于宏必须知道特质包含哪些方法,因此它必须在模块内部定义。然而,也可以生成外部特质的实现
#[proxy_enum::proxy(Animal)]
mod proxy {
enum Animal {
Cat(Cat),
Lion(Lion),
Mouse(Mouse)
}
#[external(std::string::ToString)]
trait ToString {
fn to_string(&self) -> String;
}
#[implement]
impl std::string::ToString for Animal {}
}
依赖项
~1.5MB
~33K SLoC