与 Box 层的模式匹配

Pattern matching with Box layers

我正在尝试解决 Rust 中的表达式问题。我定义了总和类型的术语:

#[derive(Clone, Debug, PartialEq)]
pub enum Term {
    True,
    False,
    Not(Box<Term>),
    ...
}

编译器和文档说递归项需要 Box,因为结构不能包含自身(无限回归),仅 &Term 不足以确定项拥有其自身子项。好的,到目前为止一切顺利。

现在我正在尝试编写一个函数,根据运算符的定义来简化术语,例如不正确=错误:

impl Term {
    pub fn simplify(self) -> Term {
        let a = self.map(Term::simplify);
        match a {
            Term::Not(Box(Term::True)) => Term::False,
            _ => a,
        }
    }

    pub fn map(self, f: fn(Term) -> Term) -> Term {
        match self {
            Term::True
            | Term::False => self,
            Term::Not(a) => Term::Not(Box::new(a.map(f))),
            _ => panic!(),
        }
    }
}

但是编译器不喜欢我到目前为止尝试过的任何版本。

Term::Not(Term::True) 无效,因为 Box 需要介于两者之间。

Term::Not(Box::new(Term::True))在做词时有效,但不能作为模式匹配表达式(不能包含函数调用)。

Term::Not(Box(Term::True)) 也无效。

在 Rust 中执行此操作的正确方法是什么?

编译器报如下错误: cannot match against a tuple struct which contains private fields。 好的,让我们寻找 Box 的定义(为简单起见,我删除了特征边界):

pub struct Box<_>(Unique<T>, A);

这看起来像错误消息中的元组。但看起来内部值也不是 public(那是错误),所以你不能像这样构造框 (Box(Term::True)).

我们能做什么? 您可以使用夜间功能 box_patterns 来创建框:

match a {
    Term::Not(box Term::True) => Term::False,
    _ => a,
}

Playground

或者,我们尝试通过取消引用来提取开箱即用的值(此处为 boxed_value),然后检查内部值:

*boxed_value == Term::True

您可以在 match:

中将其与 if guards 结合使用
match a {
    Term::Not(content) if *content == Term::True => Term::False,
    _ => a,
}

我认为这种变体更好,特别是如果您还想从 Term::False 映射到 Term::True

Playground