为什么不能使用抽象类型的具体实现来推断 ClassTag?
Why a concrete implementation of an abstract type cannot be used to infer ClassTag?
考虑以下代码:
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]可以很容易的通过类型class规则推断出来。
不幸的是,当我运行上面的代码。我得到以下结果:
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
。
考虑以下代码:
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]可以很容易的通过类型class规则推断出来。
不幸的是,当我运行上面的代码。我得到以下结果:
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
。