为什么不能使用抽象类型的具体实现来推断ClassTag?

时间:2019-06-20 22:10:28

标签: scala typeclass abstract-type

考虑以下代码:

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外,这也没有意义。是斯卡拉袋子,以后应该修理吗?

1 个答案:

答案 0 :(得分:3)

删除implicit的修饰符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