Scala 如何为模式匹配定义“StrContains.unapply”?

Scala 如何为模式匹配定义“StrContains.unapply”?,scala,pattern-matching,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) = {
  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()
}

但现在确定怎么做了。有什么想法吗?

问题是,当您执行
case StrContains(“A”)
时,编译器将首先调用
StrContains.unapply/unallyseq
(无论以何种方式定义),然后才尝试将返回的结果与
“A”
匹配。
“A”
文本本身永远不会传递给
StrContains.unapply/unplyseq
,因此它无法执行调用
s.contains(“A”)
内部
unply/unplyseq

简单地说,这意味着您需要定义不同的对象,例如
StrContainsA
/
StrContainsB
/
StrContainsC
,这显然比在s.contains(“a”)中简单地执行
情况更糟糕

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

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

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

问题是,当您执行
case StrContains(“A”)
时,编译器将首先调用
StrContains.unapply/unplyseq
(无论以何种方式定义),然后才尝试将返回的结果与
“A”
匹配。
“A”
文本本身永远不会传递给
StrContains.unapply/unplyseq
,因此它无法执行调用
s.contains(“A”)
内部
unply/unplyseq

简单地说,这意味着您需要定义不同的对象,例如
StrContainsA
/
StrContainsB
/
StrContainsC
,这显然比在s.contains(“a”)中简单地执行
情况更糟糕

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

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

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

如果第一个调用返回一个matcher对象,第二个调用是unapply的
,那么是否可以执行
case StrContains(“A”)()
?对不起,我不知道该如何执行,因为我在回答的开头给出了原因。是否可以执行
case StrContains(“A”)()
其中第一个调用返回matcher对象,第二个调用是unapply
?很抱歉,我不知道怎么做,因为我在回答的开头给出了原因。