有没有办法在不使用isInstnaceOf的情况下匹配除某种类型(或类型集)之外的所有内容?

时间:2015-08-10 16:20:36

标签: scala

我知道你可以匹配一组类似的东西,而不使用isInstanceOf

x match {
  case fooBar @ (_: Foo | _: Bar) => ???
}

但是,有没有办法匹配除了一组类型之外的任何东西?比如,匹配 xFoo的任何Bar,而不使用isInstanceOf

2 个答案:

答案 0 :(得分:3)

嗯,你可以做到

x match {
  case fooBar @(_: Foo | _: Bar) => // do nothing
  default => // do something
}

无论如何,使用isInstanceOf的唯一区别是语法,因为您将执行运行时检查。

从功能的角度来看,组合isInstanceOf / asInstanceOf与类型匹配相同。

所以(如果你真的必须)我会选择

if (!(x.isInstanceOf[Foo] || x.isInstanceOf[Bar])) {
  // do something
}

同样,没有实际的区别,它们都是处理类型的一种非常黑客的方式。除非您使用外部API而无法控制,否则我建议您更改设计并避免匹配类型。

通常类型类派上用场,但没有进一步的细节,很难确定。

答案 1 :(得分:1)

@GabrielePetronella的上述解决方案在大多数情况下都可以很好地工作,但是我添加了另一个可以在某些极端情况下提供帮助的变体。

边缘案例:

由akka演员组成的Receive函数。
考虑以下几点:

override def receive: Receive = handleFoo orElse handleBar

def handleFoo: Receive = {
  case FooObject => …
  case FooClass(value) => …
  case notFoo => 
    logger.debug(s"wasn't expecting $notFoo of type ${notFoo.getClass.getSimpleName}")
}

def handleBar: Receive = {
  case _: VeryImportantBarMsg => …
  case _: LessImportantBarMsg => …
}

handleFoo的最后一种情况将捕获所有内容,从而使orElse handleBar过时,并且显然我们不再处理VeryImportantBarMsgLessImportantBarMsg

解决方案:

使用专门的提取器对象,例如:

object NotBar {
  def unapply[T](t: T): Option[T] = t match {
    case _: VeryImportantBarMsg | _: LessImportantBarMsg => None
    case _ => Some(t)
  }
}

并像这样使用它:

def handleFoo: Receive = {
  case FooObject => …
  case FooClass(value) => …
  case NotBar(notFoo) => 
    logger.debug(s"wasn't expecting $notFoo of type ${notFoo.getClass.getSimpleName}")
}

此解决方案适用于您不希望匹配成功的情况,例如部分函数,​​akka接收,或者您发现自己多次写相同的排除类型列表_: T1 | … | _: T10等。 ..

P.S。 如果您发现自己需要此解决方案,则很可能无法对某些模型进行最佳建模。在大多数情况下,可以避免这种情况。