Scala模式匹配在嵌套的case类上并不详尽

Scala模式匹配在嵌套的case类上并不详尽,scala,pattern-matching,Scala,Pattern Matching,我有一个case类层次结构来编码一些请求和处理错误: sealed trait OpError sealed trait RequestErrorType sealed trait ProcessingErrorType final case class InvalidEndpoint(reason: String) extends RequestErrorType final case class InvalidParameters(reason: String) ext

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

  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的参数类型更改为字符串*,我不会得到错误:

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

有什么想法吗?

您可以通过未选中的注释帮助编译器:

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

但是您应该确定,您的匹配是详尽无遗的。

我认为详尽无遗的匹配在单个继承级别上起作用。
RequestErrorType
ProcessingErrorType
是构造函数的一部分,其中未检查穷尽性


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

非常有趣!不幸的是,我还没有找到答案。我一直在转来转去,但我还没有找到一个有效的解释

这里有一个简单的演示(希望您不介意):

我注意到以下两种修改都会删除警告:
1) 更改
FooOne
FooTwo
签名,以代替
ClassOne
ClassTwoImpl
他们采用
ClassOneImpl
ClassTwoImpl

2) 删除
FooOne
FooTwo
,这样只有一个case类扩展
Foo
(这导致模式匹配中只有一个case)


也许我们可以提交一个问题,看看他们怎么说?

这是一个已确认的错误。自那以后,Scala 2.12.0-M4已经修复了它。

printMatches(ProcessingError(新的ProcessingErrorType{}))
它不匹配此示例违反了
密封的
契约。关于String*参数的奇怪行为,当一个case类有一个varargs参数时,这听起来像是Scala转向了穷举检查:true,但我希望编译器帮助我找出无效实例,而不是相反的方法。;)假设我从printMatches中注释掉RequestError(InvalidParameters(reason))的匹配,那么编译器让我知道我缺少了确切的变化:“匹配可能不是穷尽的。它会在以下输入上失败:RequestError(InvalidParameters(41;)”。所以我想编译器可以找出一些嵌套继承。我把它作为一个bug归档,它已经被修复并关闭了!耶!:)有关解决方法,请参阅此注释:
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()
}