3 个版本
0.0.2 | 2021年2月22日 |
---|---|
0.0.1 | 2021年2月21日 |
0.0.0 | 2021年2月6日 |
#892 在 数学
288,937 每月下载量
在 2 个 Crates 中使用 (通过 stateright)
19KB
256 行
此 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::new
在 Never
的基础上构建一个基础变体。
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
提供的那种组合支持。例如,如果类型 A
和 B
实现了特质 T
,自定义枚举 AOrB
也可以实现该特质。遗憾的是,任何类型之间的不同选择都需要重新实现此特质,例如,需要类型 AOrCOrD
来满足另一个需要从类型 A
、C
和 D
中进行选择的情况。
通过为 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