#variant #sum #coproduct #union #either

choice

类似于 either,但支持无界数量的变体

3 个版本

0.0.2 2021年2月22日
0.0.1 2021年2月21日
0.0.0 2021年2月6日

#892数学

Download history 32775/week @ 2024-03-14 34909/week @ 2024-03-21 45048/week @ 2024-03-28 45338/week @ 2024-04-04 53522/week @ 2024-04-11 50950/week @ 2024-04-18 49525/week @ 2024-04-25 54003/week @ 2024-05-02 53611/week @ 2024-05-09 56976/week @ 2024-05-16 63778/week @ 2024-05-23 74319/week @ 2024-05-30 73105/week @ 2024-06-06 68039/week @ 2024-06-13 58621/week @ 2024-06-20 69537/week @ 2024-06-27

288,937 每月下载量
2 个 Crates 中使用 (通过 stateright)

MIT 许可证

19KB
256

crates.io docs.rs LICENSE

此 crate 类似于 either,但支持无界数量的变体。有关示例和更多详细信息,请参阅 API 文档

贡献

欢迎贡献!请 分支库,将更改推送到您的分支,并发送一个 拉取请求。除非在拉取请求中明确声明,否则所有贡献均在 MIT 许可证下共享。

许可证

Choice 版权所有 2021 Jonathan Nadal。在 MIT 许可证下提供。


lib.rs:

Rust 有一个内置的 元组 (A, B, C, ...) 来表示类型的“积”。语言缺少表示相反的泛型语法:多个类型之间的选择,也称为求和类型(或“积类型”) A + B + C + ...。此库提供了一个模式和宏来弥合这一差距。

示例

// We can instantiate a "heterogenous" `Vec` without a custom `enum`.
use choice::choice;
struct A;
struct B;
struct C;
let choices: Vec<choice![A, B, C]> = vec![
    choice!(0 <- A),
    choice!(1 <- B),
    choice!(2 <- C),
];

// Furthermore, by implementing a trait for two `Choice` forms...
use choice::{Choice, Never};
trait T {}
impl<T1: T> T for Choice<T1, Never> {}
impl<T1: T, T2: T> T for Choice<T1, T2> {}

// ... then for types that implement the trait, any `Choice` between those types also
//     implements the trait.
impl T for A {}
impl T for B {}
impl T for C {}
fn f(t: impl T) {}
for x in choices {
    f(x); // accepts values of type `choice![A, B, C]`
}

组合模式

第一次看到这个基础模式可能有点反直觉。第一步是使用 Choice::newNever 的基础上构建一个基础变体。

use choice::{Choice, Never};
let no_real_choice: Choice<u64, Never> = Choice::new(42);

Never 类型不可居住,仅用于播种模式,因此实际上在上述示例中我们有一个在 N=1 类型之间的“选择”,因为类型的实例只能持有 u64。调用 Choice::or 将类型扩展以提供更多选择,从而归纳地允许在 N+1 类型之间进行选择。

let two_types_choice1: Choice<&'static str, Choice<u64, Never>> =
    Choice::new(42).or();

您可以通过简单调用 Choice::new 来构建一个持有其他内部类型的相同 Choice 类型的实例。

let two_types_choice2: Choice<&'static str, Choice<u64, Never>> =
    Choice::new("Forty two");

上述两个示例共享一个类型,因此您可以将它们嵌入一个集合中。

let u64_or_string_vec: Vec<Choice<&'static str, Choice<u64, Never>>> = vec![
    Choice::new(42).or(),
    Choice::new("Forty two"),
    Choice::new(24).or(),
    Choice::new("Twenty four"),
];

此模式可以组合以允许额外的选择。

let many: Vec<Choice<&'static str, Choice<i8, Choice<char, Never>>>> = vec![
    Choice::new("-INFINITY"),
    Choice::new(-1         ).or(),
    Choice::new('0'        ).or().or(),
    Choice::new(1          ).or(),
    Choice::new("INFINITY" ),
];

特质组合

自定义 enum 扮演着类似的角色,但通常缺乏 Choice 提供的那种组合支持。例如,如果类型 AB 实现了特质 T,自定义枚举 AOrB 也可以实现该特质。遗憾的是,任何类型之间的不同选择都需要重新实现此特质,例如,需要类型 AOrCOrD 来满足另一个需要从类型 ACD 中进行选择的情况。

通过为 Choice<A: T, Never>Choice<A: T, B: T> 实现 T 特质,该特质也被应用于任何选择组合。请参阅上面的 示例 部分,或者参阅 stateright::actor::Actor 以获取另一个库中的真实世界示例。

choice! 宏提供了上述模式类型或值的语法糖,当有多个选择时特别有用。

let x1: choice![u64, &'static str, char, String, i8] =
    choice!(2 <- 'x');
let x2: Choice<u64, Choice<&'static str, Choice<char, Choice<String, Choice<i8, Never>>>>> =
    Choice::new('x').or().or();
assert_eq!(x1, x2);

该宏还提供了对 Choice 进行模式匹配的语法糖。Rust 无法确定基础情况 Never 是不可居住的,因此还有一个形式来满足 完备性检查器

let c: choice![u8, char] = choice!(1 <- '?');
match c {
    choice!(0 -> v) => {
        panic!("Unexpected match: {}", v);
    }
    choice!(1 -> v) => {
        assert_eq!(v, '?');
    }
    choice!(2 -> !) => {
        unreachable!();
    }
}

功能

启用 serde 功能以进行序列化/反序列化。

依赖关系

~175KB