首页 > 解决方案 > 为什么不能使用抽象类型的具体实现来推断 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包吗?

标签: scalatypeclassabstract-type

解决方案


删除修饰符implicitfor val ctg,您会看到您的代码无法编译。您不应该手动定义隐式ClassTag// TypeTagWeakTypeTag它们应该在类型已知时由编译器自动生成。

实际上,当您调用您现在定义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.


推荐阅读