#枚举 #特质 #结构体 #委托 #转换 #代表 #设计

temporary_enum_delegate_0_3_0

为枚举和结构体提供特质委托功能

1 个不稳定版本

0.3.0 2023年2月17日

#1708Rust 模式


用于 concurrent_tor

MIT/Apache

16KB
176

注意

这是一个未发布版本(存在错误)的分支,从 enum_delegate(修订版本 f99967517e925f9630735836fb1601747df9c71d)派生而来。原始作者是 Reinis Mazeiks,50U10FCA7。此包是为了解决另一个包 concurrent_tor 中的依赖冲突。由于该包依赖于 enum_delegate ^= "0.3.0",因此这是对 enum_delegate 的临时上传。

enum_delegate

gitlab crates.io docs.rs

为枚举和结构体提供特质委托功能。

注意:由于历史原因,名称包含 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 特性/方法边界,除非是标记特性,如 SizedSendSync
  • 尚未支持关联类型/常量。
  • #[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_delegateenum_dispatch 库的启发。它提供了类似的功能,但有更多的限制

  • 仅支持枚举。
  • 由于其设计限制,在crate之间使用 enum_dispatch 是不可能的。
  • 宏展开顺序相关(在某些情况下,如果宏标记的项目顺序与宏期望的不同,则代码可能会失败)。

enum_derive

使用 enum_derive::EnumInnerAsTrait 衍生一个方法,以返回指向内部值的借用指针,并将其转换为特质对象。速度较慢,但与 动态分派 更相似。

依赖项

~4MB
~83K SLoC