如何模式匹配 case classes 的父特征(或 class,或对象)?

How to pattern match the parent trait (or class, or object) of case classes?

我试图在单个 case 子句中匹配所有二元运算符,但以下代码给出了错误:

object BinOp is not a case class, nor does it have a valid unapply/unapplySeq member
Note: def unapply(a: AST.this.Expr, b: AST.this.Expr): Option[(AST.this.Expr, AST.this.Expr)] exists in object BinOp, but it cannot be used as an extractor as it has more than one (non-implicit) parameter.

遍历树的核心代码:

tree match {
    case ... other ... cases
    case BinOp(a, b) => traverse(a), traverse(b)
}

AST类如下:

sealed trait Expr

case class Num(value: java.lang.Number) extends Expr

sealed trait BinOp extends Expr {
  val a, b: Expr
}

object BinOp {
  def unapply(a: Expr, b: Expr): Option[(Expr, Expr)] = Some(a, b)
}

case class Add(a: Expr, b: Expr) extends BinOp

case class Sub(a: Expr, b: Expr) extends BinOp

case class Mul(a: Expr, b: Expr) extends BinOp

case class Div(a: Expr, b: Expr) extends BinOp

出于说明目的,代码段已大大简化。

错误消息似乎提供了信息

def unapply(a: AST.this.Expr, b: AST.this.Expr): Option[(AST.this.Expr, AST.this.Expr)] 
exists in object BinOp, but it cannot be used 
as an extractor as it has more than one (non-implicit) parameter.

so unapply 方法应该用单个参数定义,像这样说

object BinOp {
  def unapply(binOp: BinOp): Option[(Expr, Expr)] = Some(binOp.a, binOp.b)
}

您似乎对提取器对象的工作方式有误解。您可以将 unapply 视为 apply 的对偶,尽管并非总是如此。

假设您没有将 Add 作为案例 class,而 apply 方法已经为您准备好了,您将其设为普通的 class 并将 apply 伴随对象中的方法:

object Add {
  def apply(a: Expr, b: Expr): Add = ???
}

unapply 方法就是这样,但是切换了输入和输出类型(在 Option 中)。

//Could also be a Some[(Expr,Expr)], as far as I can tell
def unapply(add: Add): Option[(Expr, Expr)] = (add.a, add.b)

由于 apply 方法的输出只是一个值,因此 unapply 方法的输入是单个值,并且由于 apply 方法有多个输入,因此unapply 方法有多个输出,或者假装通过使用元组来实现。还有一点,但文档中的 this page 比我更深入。

编辑:@jwvh 指出您不需要从 unapply 方法 return 一个 Option - 它可以是具有方法 isEmptyget.

的任何类型

由于您还提到您想要对包含其他节点的任何类型的节点进行抽象,我想指出,如果您要使用模式匹配,您仍然必须使您的为每种类型的节点拥有 unapply 方法(或将其设为 case class)。