#enums #traits #macro #variant #try-from #deriving #generic

enum-conversion-derive

为枚举类型派生 From 和 TryFrom 特性的过程宏

1 个不稳定版本

0.0.1 2022年11月23日

#22#try-from


用于 enum-conversion

GPL-2.0-or-later

60KB
1K SLoC

EnumConversions

License: GPL v3

一个用于在枚举上派生自然 From / TryFrom 特性的 crate。它提供的主要宏有 #[EnumConversions]#[DeriveTryFrom]

此 crate 旨在替代 variant_access crate。它试图使用更常见的 TryFrom 特性而不是 crate 本地特性(尽管并非总是可能,见下文)。它还消除了枚举类型中的类型需要为 'static 的需求,并且不会为定义可能变得模糊的泛型类型编译(variant_access 可以编译但可能不会提供预期的行为)。

用法

给定一个枚举

#[EnumConversions]
#[DeriveTryFrom]
enum Enum {
    F1(i32),
    F2(bool),
}

将实现 TryTo 特性(由此 crate 提供)以及枚举中每个变体的 TryFrom 特性。它还将派生相反方向的 From 特性。如果没有 #[DeriveTryFrom],则默认情况下不派生 TryFrom 特性。

如果希望仅在枚举的选定变体上派生 TryFrom 特性,则可以分别标记

#[EnumConversions]
enum Enum<U> {
    F1(RefCell<U>),
    #[DeriveTryFrom]
    F2(bool),
}

此外,可以通过传递所需的错误类型和一个将 EnumConversionError 映射到该错误类型的闭包来配置 TryTo / TryFrom 特性的错误

use std::error::Error;

#[EnumConvesions(
    Error: Box<dyn Error + 'static>,
    |e| e.to_string().into()
)]
enum Enum<U> {
    F1(RefCell<U>),
    #[DeriveTryFrom]
    F2(bool),
}

限制和注意事项

这些应该在宏中进行验证,或者将导致编译器错误。对于前者,它们可以在 enum-conversion-derive 内部的单元测试中找到。后者可以在 /tests 目录下的 uncompilable_examples 子目录中找到。

枚举变体必须包含无歧义的类型。

以下类型的枚举变体在每个变体中都没有明确的类型

enum Enum {
    NamedFields{a: bool, b: i32},
    UnnamedField(bool, i32),
    Unit,
}

如果枚举中包含这些中的任何一个,宏将会引发恐慌。

任何类型都不能在多个变体中存在。

无法实现 TryFrom<bool> for bool,其中

enum Enum {
    F1(bool),
    F2(bool),
}

应该选择第一个或第二个变体吗?如果类型不能明确对应于单个字段,则宏将引发恐慌或Rust编译器将报错存在多个实现。

这个现象的更复杂例子是

enum Enum<'a, 'b, U, T> {
    Ref1(&'a U),
    Ref2(&'b T),
}

任何对TryFrom特质的通用实现也应该在特化类型 Enum<'a, 'a, bool, bool> 上工作,这是由于上述原因。在这种情况下,宏不会引发恐慌,但编译器会指出存在多个实现并报错。

在外国类型上实现外国特质。

Rust对外国特质的实现有严格的规则,请参阅错误代码E0210

特别是,不允许在外国类型上实现外国特质。由于TryFrom是一个外国特质,因此不能像这样为泛型参数推导

#[EnumConversion]
#[DeriveTryFrom]
enum Enum<U> {
    F1(RefCell<U>),
    F2(bool),
}

这就是为什么TryFrom默认不实现,并且为什么它可以全局推导或仅针对特定变体推导。特质的TryTo不是外国特质,可以用作TryInto的替代品。

依赖关系

~8–17MB
~228K SLoC