考虑以下代码:
object DelayedClassTagInference {
trait SS {
type TT <: Any
implicit val ctg: ClassTag[TT] = implicitly[ClassTag[TT]]
val fakeCtg: ClassTag[None.type] = implicitly[ClassTag[None.type]]
}
class Sub1 extends SS {
override final type TT = Int
}
class Sub2 extends SS {
override final type TT = Double
}
class Sub3 extends SS {
override final type TT = String
}
}
class DelayedClassTagInference extends FunSpec {
import DelayedClassTagInference._
it("") {
val sub1 = new Sub1()
println(sub1.fakeCtg)
println(sub1.ctg)
}
}
当Sub1和Sub2初始化时,类型TT已经确定,因此可以使用类型类规则轻松推断出ClassTag[Int]和ClassTag[Double]。
不幸的是,当我运行上面的代码时。我得到以下结果:
scala.None$
null
所以ctg的值为null,除了触发NullPointerException之外,这也没有任何意义。这是一个需要稍后修复的 scala 包吗?
最佳答案
删除 val ctg
的修饰符implicit
,您会发现您的代码无法编译。您不应该手动定义隐式 ClassTag
/TypeTag
/WeakTypeTag
,它们应该在类型已知时由编译器自动生成。
实际上,当您调用implicitly[ClassTag[TT]]
时,会使用您现在定义的隐式val ctg: ClassTag[TT]
,这就是为什么它是null
在运行时。
隐式在编译时解析,当您调用 sub1.ctg
时,会在运行时解析调用哪个 .ctg
(这就是子类型多态性的工作原理)。在编译时尚不知道它是 Sub1#ctg
。
替换
implicit val ctg: ClassTag[TT] = implicitly[ClassTag[TT]]
与
def ctg(implicit tag: ClassTag[TT]): ClassTag[TT] = implicitly[ClassTag[TT]]
并且您将在运行时拥有 Int
而不是 null
。
关于scala - 为什么抽象类型的具体实现不能用于推断 ClassTag?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56694507/