scala - 为什么不能使用抽象类型的具体实现来推断 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]。
不幸的是,当我运行上面的代码时。我得到以下结果:
scala.None$
null
所以ctg的值为null,除了触发NullPointerException之外,这也没有意义。它是一个稍后应该修复的scala包吗?
解决方案
删除修饰符implicit
for val ctg
,您会看到您的代码无法编译。您不应该手动定义隐式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
.
推荐阅读
- django - 强制Django中具有属性的最大记录数
- python - 如何在 GitLab CI 中使用 Python 和 R?
- java - PostgreSQL,Java:如何在没有关于代码位置信息的情况下打印 RAISE EXCEPTION 消息?
- angular-reactive-forms - 从 Angular 2+ 中的预定义数据填充 formControlName 复选框
- html - 当浏览器水平调整大小时,图像会缩小
- html - 如何在元素背景的一部分上显示工具提示?
- serilog - 如何捕获和记录启动错误
- aws-lambda - 在 stepfunctions 中捕获错误时向 sqs 发送消息
- firebase - PWA、Firebase 和 Google 登录:无法处理请求
- c# - WebRequest 上不允许使用错误 405 方法