Scala 为什么抽象类型的具体实现不能用于推断类标记?

Scala 为什么抽象类型的具体实现不能用于推断类标记?,scala,typeclass,abstract-type,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 {

考虑到以下准则:

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)
  }
}

所以ctg的值是null,除了触发NullPointerException之外,这也没有意义。它是一个scala包,以后应该修复吗?

删除
valctg
implicit
修饰符,您将看到您的代码没有编译。您不应该手动定义隐式
ClassTag
/
TypeTag
/
WeakTypeTag
,它们应该在类型已知时由编译器自动生成

实际上,当您隐式调用
ClassTag[TT]]
时,会使用您现在定义的隐式
val ctg:ClassTag[TT]
,这就是为什么它在运行时为
null

隐式在编译时解析,当调用
sub1.ctg
时,解析调用哪个
.ctg
发生在运行时(这就是子类型多态性的工作方式)。在编译时还不知道它是
Sub1#ctg


替换

implicit val ctg: ClassTag[TT] = implicitly[ClassTag[TT]] 


我知道,在运行时您将使用
Int
而不是
null

,但是Sub1和Sub2也在编译时解析,它们的方法签名应该根据编译时的情况进行调整,只有
val Sub1
的静态类型已知,它的运行时类型未知(无论它是
Sub1
的某个特定子类型,
.ctg
都可以在那里重写)。
Sub1
现在没有子类,但这与此无关。不确切地说,是一个精确的抽象类型(定义为=,而不是:)无论是否声明为final,都无法重写。因此,此时可以确定类标记。有关证据,请参阅本文:我不是在谈论类型成员,我是在谈论方法成员。
.ctg
是一个方法。它可以被重写。在编译时,
中的
.ctg
是未知的ub1.ctg
Sub1
.ctg
@tribbloid Replace
implicit-val-ctg:ClassTag[TT]=隐式[ClassTag[TT]]
def-ctg(implicit-tag:ClassTag[TT]):ClassTag[TT]=隐式[ClassTag[TT].
一起使用
Int
而不是
null
implicit val ctg: ClassTag[TT] = implicitly[ClassTag[TT]] 
def ctg(implicit tag: ClassTag[TT]): ClassTag[TT] = implicitly[ClassTag[TT]]