我正在编写一种规则引擎,它遍历树并为每个子树建立上下文,然后使用匹配条件来验证树并推断有关节点的信息。
我希望我可以使用嵌套匹配条件(在案例类构造函数上),并通过使用相同的构造函数属性名称来匹配外部和内部属性,如下所示:
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))
是否有办法实现这一目标,或者是采用警卫条件?
您是正确的,内部模式中的
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 语言规范有关模式匹配的章节中,标题为“稳定标识符模式”的部分中进行了描述:
一个稳定标识符模式是一个稳定标识符r。 r 的类型必须符合模式的预期类型。该模式与任何值 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 } }
这里,前三个模式是稳定标识符模式,而最后一个是可变模式。