1 个不稳定版本
0.3.0 | 2023年2月17日 |
---|
#1708 在 Rust 模式
16KB
176 行
注意
这是一个未发布版本(存在错误)的分支,从 enum_delegate(修订版本 f99967517e925f9630735836fb1601747df9c71d
)派生而来。原始作者是 Reinis Mazeiks,50U10FCA7。此包是为了解决另一个包 concurrent_tor
中的依赖冲突。由于该包依赖于 enum_delegate ^= "0.3.0"
,因此这是对 enum_delegate
的临时上传。
enum_delegate
为枚举和结构体提供特质委托功能。
注意:由于历史原因,名称包含 enum_*
部分,但不仅限于枚举。
[dependencies]
enum_delegate = "0.4"
示例
use enum_delegate::delegate;
#[delegate(for(LastName))]
trait AsStr {
fn as_str(&self) -> &str;
}
impl AsStr for String {
fn as_str(&self) -> &str {
self
}
}
#[delegate(derive(AsStr))]
struct FirstName(String);
#[delegate]
struct LastName {
name: String,
}
#[delegate(derive(AsStr))]
enum Name {
First(FirstName),
Last(LastName),
}
fn main() {
let name = Name::First(FirstName("John".to_string()));
assert_eq!(name.as_str(), "John");
let name = Name::Last(LastName {
name: "Doe".to_string(),
});
assert_eq!(name.as_str(), "Doe");
}
工作原理
包提供了几个定义
delegate
宏 - 在新类型结构体或枚举上推导特质,在内部类型上调用它。Convert
特质 - 将枚举或结构体转换为表示 "其任何变体" 的类型。
#[delegate]
在类型上的展开
为枚举/结构体实现 Convert
特质,允许将其转换为 "其任何变体" 类型。
来源
#[delegate]
enum Name {
First(FirstName),
Last {
name: LastName,
},
}
生成
注意:示例简化以提高可读性。
impl Convert for Name {
type Output = Either<FirstName, LastName>;
fn convert(self) -> Self::Output {
match self {
Name::First(first_name) => Either::Left(first_name),
Name::Last { name } => Either::Right(name),
}
}
}
#[delegate]
在特质上的展开
为任何实现了 Convert
特质的类型实现特质,其中 "任何变体" 实现目标特质。即生成的 impl
中的每个方法将 self
转换为 "其任何变体",并在其上调用目标特质的函数。
来源
#[delegate]
trait AsStr {
fn as_str(&self) -> &str;
}
生成
注意:示例简化以提高可读性。
// Implementation for "any variant of enum or struct" type.
impl<L: AsStr, R: AsStr> AsStr for Either<L, R> {
fn as_str(&self) -> &str {
match self {
Either::Left(left) => left.as_str(),
Either::Right(right) => right.as_str(),
}
}
}
// Implementation for any type that implements `Convert` trait.
impl<T> AsStr for T
where
T: Convert,
T::Output: AsStr,
{
fn as_str(&self) -> &str {
let this = self.convert(); // convert type to "any of its variant".
this.as_str() // call the method.
}
}
限制
- 结构体/枚举和特质都应使用
#[delegate]
宏属性标记。 - 结构体或枚举变体应仅包含单个字段。
- 特质方法必须具有无类型接收器。
- 尚不支持外部(远程)类型或特质的实现。
- 尚未支持超特性或
Self
特性/方法边界,除非是标记特性,如Sized
、Send
或Sync
。 - 尚未支持关联类型/常量。
#[delegate(for(Enum<Generics>))]
仅支持具体泛型类型。
替代方案
动态分派
Rust 使用特质对象进行动态分派的机制,这增加了运行时开销。
示例
trait AsStr {
fn as_str(&self) -> &str;
}
impl AsStr for String {
fn as_str(&self) -> &str {
self
}
}
struct FirstName(String);
impl AsStr for FirstName {
fn as_str(&self) -> &str {
&self.0
}
}
fn do_something_with_string(s: &dyn AsStr) {
println!("{}", s.as_str());
}
fn main() {
let name = "John".to_string();
do_something_with_string(&name);
let name = FirstName(name);
do_something_with_string(&name);
}
enum_dispatch
enum_delegate
受 enum_dispatch 库的启发。它提供了类似的功能,但有更多的限制
- 仅支持枚举。
- 由于其设计限制,在crate之间使用
enum_dispatch
是不可能的。 - 宏展开顺序相关(在某些情况下,如果宏标记的项目顺序与宏期望的不同,则代码可能会失败)。
enum_derive
使用 enum_derive::EnumInnerAsTrait
衍生一个方法,以返回指向内部值的借用指针,并将其转换为特质对象。速度较慢,但与 动态分派 更相似。
依赖项
~4MB
~83K SLoC