想象一个结构...
struct Pair {
letter: Letter,
number: Number,
}
enum Letter {A, B, C}
enum Number {One, Two, Three}
此结构中的组合总数为 3 x 3 = 9,但是,我只想使其中的一些成为可能。比如说,我允许所有组合存在,但 {C, Three} 不能存在,无论出于何种原因。
Rust 中的类型系统如何帮助我实现这一点,如果我有一个 Pair 的构造函数...
impl Pair {
fn new(letter : Letter, number : Number) -> Pair {
...
}
}
然后在我的主要功能中我做...
Pair::new(Letter::C, Number::Three);
编译器引发编译时错误而不是在运行时恐慌?
类型系统处理类型,而不是值[1]。为了添加限制,您需要将其构建到类型中。
例如,此设置对您在问题中提到的限制进行编码:
enum Pair {
A(Number),
B(Number),
C(NumberForC),
}
enum Number {
One,
Two,
Three,
}
enum NumberForC {
One,
Two,
}
Pair
的每个变体都是构造函数,但您不能使用您描述的签名实现 new
函数。
另一个公式是为每个数据变体添加类型并使用特征来编码约束。您可以将这些用作
Pair
构造函数的参数:
// Using Pair, Letter and Number as provided in the question
impl<N, L> Pair<N, L>
where
L: Assoc<N> + Into<Letter>,
N: Into<Number>,
{
fn new(letter: L, number: N) -> Self {
Pair {
letter: letter.into(),
number: number.into(),
}
}
}
// Use macros to generate the remainder:
struct A;
struct B;
struct C;
struct One;
struct Two;
struct Three;
trait Assoc<N> {}
impl Assoc<One> for A {}
impl Assoc<Two> for A {}
impl Assoc<Three> for A {}
impl Assoc<One> for B {}
impl Assoc<Two> for B {}
impl Assoc<Three> for B {}
impl Assoc<One> for C {}
impl Assoc<Two> for C {}
impl From<One> for Number {
fn from(_: One) -> Self {
Self::One
}
}
impl From<Two> for Number {
fn from(_: Two) -> Self {
Self::Two
}
}
impl From<Three> for Number {
fn from(_: Three) -> Self {
Self::Three
}
}
impl From<A> for Letter {
fn from(_: A) -> Self {
Self::A
}
}
impl From<B> for Letter {
fn from(_: B) -> Self {
Self::B
}
}
impl From<C> for Letter {
fn from(_: C) -> Self {
Self::C
}
}
这会在您需要编写的类型和特征实现的数量上快速爆炸,但您可以潜在地使用宏来控制它。
[1] 实际上它可以使用一些整数类型作为约束,使用 const 泛型,但这有点受限,不会在这里帮助你。