Scala模式匹配在嵌套案例类中并非详尽无遗

时间:2015-12-22 13:16:16

标签: scala pattern-matching

我有一个案例类层次结构来编码一些请求和处理错误:

  sealed trait OpError
  sealed trait RequestErrorType
  sealed trait ProcessingErrorType

  final case class InvalidEndpoint(reason: String) extends RequestErrorType
  final case class InvalidParameters(reason: String) extends RequestErrorType

  final case class InvalidFormat(response: String) extends ProcessingErrorType
  final case class EntityNotFound(id: Long) extends ProcessingErrorType

  final case class RequestError(errorType: RequestErrorType) extends OpError
  final case class ProcessingError(errorType: ProcessingErrorType) extends OpError

如果我在所有模式中编写简单匹配:

  def printMatches(error: OpError): Unit = error match {
    case RequestError(InvalidEndpoint(reason)) => //print something
    case RequestError(InvalidParameters(reason)) => //print something
    case ProcessingError(InvalidFormat(format)) => //print something
    case ProcessingError(EntityNotFound(entityId)) => //print something
  }

编译器给我一个关于缺少匹配的警告:

 match may not be exhaustive.
 It would fail on the following input: ProcessingError(_)
 def printMatches(error: OpError): Unit = error match {

但ProcessingError接收的ProcessingErrorType只有两个扩展名:InvalidFormat和EntityNotFound,两者都在模式匹配中考虑。我错过了什么?

更奇怪的是,如果我将InvalidParameters或InvalidEndpoint的参数类型更改为String *,我就不会收到错误:

final case class InvalidParameters(reason: String*) extends RequestErrorType

有什么想法吗?

4 个答案:

答案 0 :(得分:4)

这是一个确认的错误。 I filed a bug report for this已经为Scala 2.12.0-M4修复了它。

答案 1 :(得分:1)

非常有趣!不幸的是,我还没找到答案。我一直在围绕着http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html#constructor-patterns,但我还没有真正找到有效的解释。

这是一个更简单的演示(希望你不要介意):

sealed abstract class ClassOne
case class ClassOneImpl() extends ClassOne

sealed abstract class ClassTwo()
case class ClassTwoImpl() extends ClassTwo

sealed abstract class Foo
case class FooOne(x: ClassOne) extends Foo
case class FooTwo(x: ClassTwo) extends Foo

def printMatches(st: Foo): Unit = st match {
  case FooOne(ClassOneImpl()) => println()
  case FooTwo(ClassTwoImpl()) => println()
}

我观察到以下两个修改中的每一个都删除了警告:
1)更改FooOneFooTwo个签名,以便取代ClassOneClassTwo,而不是ClassOneImplClassTwoImpl 2)删除FooOneFooTwo,以便只有一个案例类扩展Foo(在模式匹配中仅导致一个案例)。

也许我们可以提交问题,看看他们说了什么?

答案 2 :(得分:0)

您可以使用未经检查的注释来帮助编译器:

... = (error: @unchecked) match ...

但你应该确定,你的比赛是详尽无遗的。

答案 3 :(得分:0)

我认为详尽匹配适用于单个继承级别。 RequestErrorTypeProcessingErrorType是构造函数的一部分,其中未检查详尽性。

你可以从阅读代码中看到它,但似乎编译器没有。