Scala嵌套match模式匹配遇变量遮蔽,如何无需守卫条件实现匹配?
解决方案:避免嵌套match变量遮蔽的几种方式
你的猜测完全正确——内部match中的case Foo(num, text)会创建新的局部变量,遮蔽了外部从context提取的num和text,所以任何Foo实例都会匹配第一个case,导致全部返回"Exact match"。
不用显式守卫的话,有以下几种实现方式:
1. 使用反引号引用外部变量
在模式匹配中,用反引号包裹变量名,可以告诉Scala这是一个已存在的变量,而非要绑定的新变量。修改后的代码如下:
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(_, `text`) => "Text match" case Foo(`num`, _) => "Number match" case Foo(_, _) => "No match" } } } items.map(i => matchFoo(context, i)) // 输出:List(Exact match, Number match, Text match, No match)
这里的Foo(num, text)会匹配item的属性与context的num、text完全相等的情况,不会创建新变量。
2. 合并为单一层级的元组模式匹配
把context和item打包成元组,用一次match完成所有判断,从根本上避免嵌套带来的变量遮蔽问题:
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, item) match { case (Foo(num, text), Foo(`num`, `text`)) => "Exact match" case (Foo(num, _), Foo(`num`, _)) => "Number match" case (Foo(_, text), Foo(_, `text`)) => "Text match" case _ => "No match" } } items.map(i => matchFoo(context, i)) // 输出:List(Exact match, Number match, Text match, No match)
这种方式代码更简洁,逻辑更清晰,也避免了嵌套match的变量作用域问题。
3. 利用case class的属性直接判断
如果你不需要严格依赖模式匹配语法,也可以直接通过case class的属性访问来判断:
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 = { if (item == context) "Exact match" else if (item.num == context.num) "Number match" else if (item.text == context.text) "Text match" else "No match" } items.map(i => matchFoo(context, i)) // 输出:List(Exact match, Number match, Text match, No match)
这种方式最直观,case class默认实现了equals方法,可以直接用来判断完全匹配。
内容的提问来源于stack exchange,提问作者David Regan
相关产品推荐
相关产品推荐

