如何模式匹配 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
- 它可以是具有方法 isEmpty
和 get
.
的任何类型
由于您还提到您想要对包含其他节点的任何类型的节点进行抽象,我想指出,如果您要使用模式匹配,您仍然必须使您的为每种类型的节点拥有 unapply
方法(或将其设为 case class)。
我试图在单个 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
- 它可以是具有方法 isEmpty
和 get
.
由于您还提到您想要对包含其他节点的任何类型的节点进行抽象,我想指出,如果您要使用模式匹配,您仍然必须使您的为每种类型的节点拥有 unapply
方法(或将其设为 case class)。