scala - 为什么抽象类型的具体实现不能用于推断 ClassTag?

标签 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之外,这也没有任何意义。这是一个需要稍后修复的 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/

相关文章:

scala - 抽象类型+自身类型+类型覆盖,错误 "Value xxx is not a member of Component.this.T"

scala - Scala 函数中参数集顺序的规则和实践

scala - 在 sbt 0.10 中为 specs2 测试配置 junitxml 输出

unit-testing - 是否可以使用类型类将 `ReaderT (IO a) IO a` 更改为 `ReaderT (i a) IO a` ?

haskell——有什么方法可以为大致元组同构数据类型生成 "deriving"实例?

haskell - 在haskell中,为什么我需要指定类型约束,为什么编译器不能弄清楚它们?

scala - 从抽象特征方法返回相同的类型

generics - 有没有使用泛型无法实现的 scala 抽象类型使用示例?

scala - 两个分区数据帧之间的 Spark 共置连接

scala - 如何在 Scala 中扩展 map ?