为何Scala非穷尽模式匹配未触发编译警告?
为什么Scala编译时未给出非穷尽模式匹配警告?
问题场景
编译以下Scala代码时,控制台没有输出非穷尽模式匹配的警告:
package example object Hello extends App { class Problem extends Exception { override def getCause() : Throwable = new NotImplementedError("I'm not done") } handle(new Problem) def handle(ex: Exception): Unit = { println("handler called: %s".format(ex)) val result = ex.getCause match { case null => println("null") case e : Exception => println("except") // no warning about the match not being exhaustive // case t : Throwable => println("throw") } } }
但运行代码时会抛出MatchError,栈跟踪如下:
scala.MatchError: scala.NotImplementedError: I'm not done (of class scala.NotImplementedError) at example.Hello$.handle(Hello.scala:13) at example.Hello$.delayedEndpoint$example$Hello$1(Hello.scala:9) at example.Hello$delayedInit$body.apply(Hello.scala:3) at scala.Function0.apply$mcV$sp(Function0.scala:39) at scala.Function0.apply$mcV$sp$(Function0.scala:39) at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17) at scala.App.$anonfun$main$1(App.scala:76) at scala.App.$anonfun$main$1$adapted(App.scala:76) at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:563) at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:561) at scala.collection.AbstractIterable.foreach(Iterable.scala:926) at scala.App.main(App.scala:76) at scala.App.main$(App.scala:74) at example.Hello$.main(Hello.scala:3) at example.Hello.main(Hello.scala)
取消注释case t : Throwable => println("throw")后,程序正常输出throw。
原因分析
这是Scala编译器对Throwable类型模式匹配的特殊处理逻辑导致的:
- Scala的非穷尽模式匹配警告基于编译期可见的静态类型层级检查,但针对
Throwable这种顶级异常类型,编译器不会强制要求覆盖所有子类分支。 Throwable有两个核心直接子类:Exception(业务代码通常处理的异常)和Error(JVM层面的致命错误,比如NotImplementedError、OutOfMemoryError等)。编译器默认认为Error属于不应由业务代码捕获处理的致命情况,因此不会将Error分支纳入非穷尽检查的强制范围。- 你的代码只匹配了
null和Exception,但运行时getCause()返回的NotImplementedError属于Error类型,不在匹配分支中,因此抛出MatchError;但编译器不会因为遗漏Error分支而触发警告。
内容的提问来源于stack exchange,提问作者Tim Stewart
相关产品推荐
相关产品推荐

