引发编译时错误以限制 Rust 中结构的可能排列

问题描述 投票:0回答:1

想象一个结构...

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);
编译器引发编译时错误而不是在运行时恐慌?

rust types enums strong-typing
1个回答
0
投票

类型系统处理类型,而不是值[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 泛型,但这有点受限,不会在这里帮助你。

© www.soinside.com 2019 - 2024. All rights reserved.