Scala嵌套匹配模式匹配

eblbsuwk  于 12个月前  发布在  Scala
关注(0)|答案(1)|浏览(107)

我正在编写一种规则引擎,它遍历树并为每个子树建立上下文,然后使用匹配条件来验证树并推断有关节点的信息。
我希望我可以使用嵌套的匹配条件(在case类构造函数上),并通过使用相同的构造函数属性名称来匹配外部和内部属性,如下所示:

val context = Foo(42, "Hello, World")
val items = List(
  Foo(42, "Hello, World"),
  Foo(42, "Bar"),
  Foo(24, "Hello, World"),
  Foo(2, "Goodbye")
)

def matchFoo(context: Foo, item: Foo): String = {
  context match {
    case Foo(num, text) =>
      item match {
        case Foo(num, text)           => "Exact match"
        case Foo(otherNum, text)      => "Text match"
        case Foo(num, otherText)      => "Number match"
        case Foo(otherNum, otherText) => "No match"
      }
  }

}

items.map(i => matchFoo(context, i))

但我只得到了4个“完全匹配”的结果。我猜测case Foo(num,text)的内部匹配隐藏了外部num,text变量,因此匹配任何Foo项。
我可以通过使用显式的保护条件来解决这个问题,但这是我试图避免的:

val context = Foo(42, "Hello, World")
val items = List(
  Foo(42, "Hello, World"),
  Foo(42, "Bar"),
  Foo(24, "Hello, World"),
  Foo(2, "Goodbye")
)

def matchFoo(context: Foo, item: Foo): String = {
  context match {
    case Foo(num, text) =>
      item match {
        case Foo(otherNum, otherText) if otherNum == num && otherText == text => "Exact match"
        case Foo(otherNum, _) if otherNum == num => "Number match"
        case Foo(_, otherText) if otherText == text => "Text match"
        case _ => "No match"
      }
  }

}

items.map(i => matchFoo(context, i))

有没有办法做到这一点,或者是警卫条件的方式去?

f45qwnt8

f45qwnt81#

您是正确的,内部模式中的numtext创建了隐藏外部变量的新变量绑定,而不是使用外部变量的值作为匹配值。你可以用反引号(`)来引用这些名称,以获得你想要的行为:

case class Foo(num: Int, text: String)
val context = Foo(42, "Hello, World")
val items = List(
  Foo(42, "Hello, World"),
  Foo(42, "Bar"),
  Foo(24, "Hello, World"),
  Foo(2, "Goodbye")
)

def matchFoo(context: Foo, item: Foo): String = {
  context match {
    case Foo(num, text) =>
      item match {
        case Foo(`num`, `text`)       => "Exact match"
        case Foo(otherNum, `text`)    => "Text match"
        case Foo(`num`, otherText)    => "Number match"
        case Foo(otherNum, otherText) => "No match"
      }
  }

}

items.map(i => matchFoo(context, i))

输出量:

val res0: List[String] = List(Exact match, Number match, Text match, No match)

这种语法在Scala语言规范中关于模式匹配的章节中的“稳定标识符模式”一节中进行了描述:
稳定标识符模式是稳定标识符r。r 的类型必须符合模式的预期类型。该模式匹配任何值 v,使得 r == v(参见此处)。
为了解决与变量模式的语法重叠,稳定的标识符模式可能不是以小写字母开头的简单名称。但是,可以将这样的变量名括在反引号中;则将其视为稳定标识符模式。
例如,考虑以下类定义:

class C { c =>
  val x = 42
  val y = 27
  val Z = 8
  def f(x: Int) = x match {
    case c.x => 1  // matches 42
    case `y` => 2  // matches 27
    case Z   => 3  // matches 8
    case x   => 4  // matches any value
  }
}

这里,前三个模式是稳定的标识符模式,而最后一个是可变的模式。

相关问题