Scala 嵌套匹配模式匹配

问题描述 投票:0回答:1

我正在编写一种规则引擎,它遍历树并为每个子树建立上下文,然后使用匹配条件来验证树并推断有关节点的信息。

我希望我可以使用嵌套匹配条件(在案例类构造函数上),并通过使用相同的构造函数属性名称来匹配外部和内部属性,如下所示:

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))

是否有办法实现这一目标,或者是采用警卫条件?

scala pattern-matching
1个回答
1
投票

您是正确的,内部模式中的

num
text
创建了隐藏外部变量的新变量绑定,而不是使用外部变量的值作为匹配的值。您可以用反引号 (`) 引用名称以获得您想要的行为:

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 语言规范有关模式匹配的章节中,标题为“稳定标识符模式”的部分中进行了描述

一个稳定标识符模式是一个稳定标识符rr 的类型必须符合模式的预期类型。该模式与任何值 v 匹配,使得 r == v (参见 here)。

为了解决与变量模式的语法重叠问题,稳定的标识符模式可能不是以小写字母开头的简单名称。但是,可以将此类变量名称括在反引号中;然后它被视为稳定的标识符模式。

示例 考虑以下类定义:

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
  }
}

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

© www.soinside.com 2019 - 2024. All rights reserved.