【问题标题】:Pattern matching with more than one match多于一个匹配的模式匹配
【发布时间】:2011-09-27 07:29:40
【问题描述】:

考虑以下 Scala 代码。

val a = "both"

a match {
    case "both" | "foo" => println ("foo")   // case 1
    case "both" | "bar" => println ("bar")   // case 2
}

我希望match 工作,这样如果a == "both",Scala 将执行这两种情况。这是可能的还是有其他方法可以实现我想要的?

【问题讨论】:

标签: scala pattern-matching


【解决方案1】:

标准模式匹配总是只匹配一种情况。通过使用模式可以被视为部分函数这一事实(参见Language Specification,第 8.5 节,模式匹配匿名函数)并定义自己的匹配运算符,你可以接近你想要的,不过:

class MatchAll[S](scrutinee : =>S) {
  def matchAll[R](patterns : PartialFunction[S,R]*) : Seq[R] = {
    val evald : S = scrutinee
    patterns.flatMap(_.lift(evald))
  }
}

implicit def anyToMatchAll[S](scrut : =>S) : MatchAll[S] = new MatchAll[S](scrut)

def testAll(x : Int) : Seq[String] = x matchAll (
  { case 2 => "two" },
  { case x if x % 2 == 0 => "even" },
  { case x if x % 2 == 1 => "neither" }
)

println(testAll(42).mkString(",")) // prints 'even'
println(testAll(2).mkString(","))  // prints 'two,even'
println(testAll(1).mkString(","))  // prints 'neither'

语法与平常略有不同,但对我来说,这样的结构仍然是 Scala 强大功能的见证。

你的例子现在写成:

// prints both 'foo' and 'bar'
"both" matchAll (
  { case "both" | "foo" => println("foo") },
  { case "both" | "bar" => println("bar") }
)

编辑huynhjl指出他给this question的答案惊人地相似。)

【讨论】:

  • 这让我想起了stackoverflow.com/questions/6720205/…。 by name => S 有什么好处?
  • 哇。我不知道这是在那里。感谢您添加链接。我将 by name 参数用于(不太可能)有人会在使用之前构造 MatchAll 实例的情况,以便对审查员的评估产生的潜在影响出现在正确的位置。
【解决方案2】:

冒着成为明显队长的风险,在这种情况下,最简单的方法就是忘记模式匹配并使用if

if (a == "both" || a == "foo") println("foo")
if (a == "both" || a == "bar") println("bar") 

如果a == 的重复让你担心,你可以改写

if (Set("both", "foo")(a)) println("foo")
if (Set("both", "bar")(a)) println("bar")

利用Set 上的apply 方法与contains 的作用相同,而且更短一点。

【讨论】:

    【解决方案3】:

    match 执行一种,并且只执行一种情况,因此您不能在匹配中作为or 执行此操作。但是,您可以使用列表和map/foreach

    val a = "both"
    (a match {
      case "both" => List("foo", "bar")
      case x => List(x)
    }) foreach(_ match {
      case "foo" => println("foo")
      case "bar" => println("bar")
    })
    

    而且您没有复制任何重要的代码(在本例中为printlns)。

    【讨论】:

      【解决方案4】:

      只需匹配两次:

      val a = "both"
      
      a match {
          case "both" | "foo" => println ("foo")   // Case 1
      }
      a match {
          case "both" | "bar" => println ("bar")   // Case 2
      }
      

      【讨论】:

        【解决方案5】:

        一种可能的方法是:

        val a = "both"
        
        a match {
          case "foo" => println ("foo")   // Case 1
          case "bar" => println ("bar")   // Case 2
          case "both" => println ("foo"); println ("bar")
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-08-04
          • 1970-01-01
          • 2011-10-20
          • 1970-01-01
          • 2013-03-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多