Scala中MatchError: null异常:泛型模式匹配为何失败?
Scala类型默认值函数的模式匹配失败问题
首先我们有一个可以返回任意类型默认值的函数:
import scala.compiletime.uninitialized def default[T]:T = { class Default[T] { var value:T = uninitialized } Default[T].value } default[Double] // Double = 0.0 default[Boolean] // Boolean = false default[Int] // Int = 0
但以下基于模式匹配实现的函数却无法正常运行:
def matchType[T]():T = { default[T] match { case d:Double => d case i:Int => i case b:Boolean => b } } matchType[Double]() // 抛出异常: // scala.MatchError: null // ammonite.$sess.cmd37$.matchType(cmd37.sc:5) // ammonite.$sess.cmd37$.<clinit>(cmd37.sc:9)
模式匹配失败的原因
问题核心在于泛型擦除和default函数的实现逻辑:
单独调用
default[T]的正常行为:
当直接调用default[Double]这类指定具体类型的调用时,编译器会针对T=Double进行代码特化。此时Default[Double]中的var value:Double是基本类型变量,JVM会自动将其初始化为对应基本类型的默认值(0.0),最终返回正确结果。泛型函数中调用
default[T]的异常行为:
在matchType这个泛型函数里,JVM的泛型擦除机制会抹去T的具体类型信息,编译后的代码中T会被视为Object(因为没有指定类型上界)。此时Default[T]中的var value:T会被当作Object类型变量,未初始化的Object类型变量默认值是null。模式匹配的运行时检查逻辑:
模式匹配是运行时行为,此时default[T]返回的是null,而case d:Double这类类型匹配会检查null是否属于Double(实际是装箱后的java.lang.Double)类型实例,显然null不属于任何引用类型的实例,因此所有case都不匹配,最终抛出MatchError。
简言之,泛型擦除导致default[T]在泛型函数内部无法生成对应值类型的初始化逻辑,返回了null,而模式匹配无法处理null的类型匹配,最终触发异常。
内容的提问来源于stack exchange,提问作者George Chen
相关产品推荐
相关产品推荐

