我坚持使用多级模式匹配,在下面的代码中我想匹配一个特定情况,在几个级别检查" cfe是Assignment,assignmentCfe.getRight是BinaryExpression,等等& #34;,解决方案看起来很难看,我希望Scala能为我提供更好的东西。 :)
def findAll(cfg: Cfg, consumer: Consumer[Violation]): Unit = {
val fa = new FlowAnalyzer
val states = fa.analyze(cfg)
states.foreach { case (cfe, state) => cfe match {
case assign: Assignment => assign.getRight match {
case expression: BinaryExpression => expression.getOperator match {
case Operator.Div | Operator.Rem => processDivisions()
case _ =>
}
case _ =>
}
case _ =>
}
case _ =>
}
}
如何摆脱这些空的默认情况?
另一种方法是使用嵌套条件,但IntelliJ IDEA让我将这些条件替换回模式匹配
states.foreach { case (cfe, state) => if (cfe.isInstanceOf[Assignment]) {
val assignment = cfe.asInstanceOf[Assignment]
if (assignment.getRight.isInstanceOf[BinaryExpression]) {
val expression = assignment.getRight.asInstanceOf[BinaryExpression]
if (expression.getOperator == Operator.Div || expression.getOperator == Operator.Rem) processDivisions()
}
}}
答案 0 :(得分:3)
Assignment
和BinaryExpression
本身是案例类吗?或者他们有相应的unapply方法?如果是这样,那么您可以嵌套模式匹配并忽略您不关心的字段。例如,像:
def findAll(cfg: Cfg, consumer: Consumer[Violation]): Unit = {
val fa = new FlowAnalyzer
val states = fa.analyze(cfg)
states.foreach {
case (Assignment(_, BinaryExpression(_, _, Operator.Div | Operator.Rem)), _) => processDivisions()
case _ =>
}
}
这至少会将默认匹配的数量减少到1。
如果这些不是案例类或没有提取器,那么如果这是代码中常见的(反)模式,则可以考虑编写自己的类:http://docs.scala-lang.org/tutorials/tour/extractor-objects.html
答案 1 :(得分:0)
另一个想法是你可以使用“pimp my library”模式来定义从任何对象到可以进行某种部分匹配的类的隐式转换:
class PartialMatcher[A](a: A) {
def partialMatch(f: PartialFunction[A, Unit]): Unit = if (f.isDefinedAt(a)) f(a)
}
implicit def makePartialMatcher[A](a: A) = new PartialMatcher(a)
然后用partialMatch
替换所有这些匹配:
def findAll(cfg: Cfg, consumer: Consumer[Violation]): Unit = {
val fa = new FlowAnalyzer
val states = fa.analyze(cfg)
states.foreach { case (cfe, state) => cfe partialMatch {
case assign: Assignment => assign.getRight partialMatch {
case expression: BinaryExpression => expression.getOperator partialMatch {
case Operator.Div | Operator.Rem => processDivisions()
}
}
}}
}
请注意,还有其他原因可以避免这种情况......过度使用隐式转换会使理解代码变得更加困难。这是一种风格选择。
答案 2 :(得分:0)
使用.collect
:
def findAll(cfg: Cfg, consumer: Consumer[Violation]): Unit = {
val fa = new FlowAnalyzer
val states = fa.analyze(cfg)
states.collect { case (assign: Assignment, _) =>
assign.getRight
}.collect { case expression: BinaryExpression =>
expression.getOperator
}.collect { case Operator.Div | Operator.Rem =>
processDivisions
}