如何为模式匹配定义`StrContains.unapply`?

时间:2015-08-10 15:36:27

标签: scala pattern-matching

我的代码中有一个方法,需要检查传递的字符串是否包含一些指定的字符,然后执行某些操作。

代码看起来像:

def check(str: String) = {
  if(str.contains("A")) {
    doSomething()
  } else if(str.contains("B")) {
    doSomething()
  } else if(str.contains("C")) {
    doSomething()
  } else {
    doSomething()
  }
}

我想尝试模式匹配,但不是很满意:

def check(str: String) = str match {
  case s if s.contains("A") => doSomething()
  case s if s.contains("B") => doSomething()
  case s if s.contains("C") => doSomething()
  case _ => doSomething()
}

我希望我可以定义一个StrContains.unapply来像这样使用它:

def check(str: String) = str match {
  case StrContains("A") => doSomething()
  case StrContains("B") => doSomething()
  case StrContains("C") => doSomething()
  case _ => doSomething()
}

但现在确定如何做到这一点。有什么想法吗?

1 个答案:

答案 0 :(得分:4)

问题在于,当您执行case StrContains("A")时,编译器将首先调用StrContains.unapply/unapplySeq(无论以何种方式定义),然后尝试将返回的结果与"A"进行匹配。 "A"字面值本身永远不会传递给StrContains.unapply/unapplySeq,因此无法在s.contains("A")内执行调用unapply/unapplySeq

简单地说,这意味着您需要定义不同的对象,例如StrContainsA / StrContainsB / StrContainsC,这显然比简单地执行{{1}更糟糕的情况}。

然而,有一种替代(并且有点人为)的解决方案允许定义单个提取器,同时仍然能够指定内联要匹配的子字符串,这就是利用以下事实: scala支持基于字符串插值定义提取器:

case s if s.contains("A")

用法:

implicit class ContainsContext (val sc : StringContext) {
  object StrContains {
    def unapply(str: String): Boolean = {
      val substr: String = sc.parts.mkString
      str.contains(substr)
    }
  }
}