【问题标题】:Why a concrete implementation of an abstract type cannot be used to infer ClassTag?为什么不能使用抽象类型的具体实现来推断 ClassTag?
【发布时间】:2019-06-20 22:10:28
【问题描述】:

考虑以下代码:

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包?

【问题讨论】:

    标签: scala typeclass abstract-type


    【解决方案1】:

    删除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

    【讨论】:

    • 我知道,但是 Sub1 和 Sub2 也是在编译时解析的,它们的方法签名应该相应地适应
    • 在编译时只知道val sub1的静态类型,它的运行时类型是未知的(无论是Sub1的特定子类型,.ctg可以在那里被覆盖)。 Sub1 现在没有子类,但这无关紧要。
    • 不确切地说,一个确切的抽象类型(由 = 定义,而不是 <:>:)不能被覆盖,无论是否声明为 final。因此,此时已经可以确定 ClassTag。请参阅此帖子以获取证据:stackoverflow.com/questions/55151774/…
    • 我不是在谈论类型成员,我是在谈论方法成员。 .ctg 是一种方法。它可以被覆盖。在编译时,不知道sub1.ctg 中的.ctgSub1.ctg
    • @tribbloid 将implicit val ctg: ClassTag[TT] = implicitly[ClassTag[TT]] 替换为def ctg(implicit tag: ClassTag[TT]): ClassTag[TT] = implicitly[ClassTag[TT]],您将在运行时使用Int 而不是null
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多