获取抽象类型的名称

Get name of abstract type

我正在尝试创建一个特征,该特征将提供在子class中添加的抽象类型的名称:

trait T {
  type T
  def myClassOf[T:ClassTag] = implicitly[ClassTag[T]].runtimeClass
  def getType = {
    myClassOf[T].getSimpleName
  }
}

class TT extends T {
  type T = String
}

然而,编译失败:

Error:(7, 15) not enough arguments for method myClassOf: (implicit evidence: scala.reflect.ClassTag[T.this.T])Class[_].
Unspecified value parameter evidence.
    myClassOf[T].getSimpleName
             ^

但是如果我将 getType 方法移动到子 class 方法,它工作正常。有人可以解释为什么以及是否有办法从 sub-class?

进行此调用

在你调用myClassOf[T]的地方,T仍然是抽象的,所以编译器不能为它生成一个ClassTag。您可以通过延迟生成 ClassTag[T] 直到知道 T 来修复它。

trait Trait {
  type T
  def myClassOf[A:ClassTag] = implicitly[ClassTag[A]].runtimeClass
  def getType(implicit tag: ClassTag[T]) = {
    myClassOf[T].getSimpleName
  }
}

class Sub extends Trait {
  type T = String
}

如果由于某种原因无法添加隐式参数,我认为最好的方法可能是要求在子类中实现某些方法 getClassT。由于它的 return 类型是 Class[T],因此很难在子类中提供错误的实现。

trait Trait {
  type T
  def getType = {
    getClassT.getSimpleName
  }
  def getClassT: Class[T]
}

class Sub extends Trait {
  type T = String
  def getClassT = classOf[T]
}

请注意,从 scala 2.10 开始,上面的答案虽然很好,但现在已经过时了。 现在首选的方法是使用 TypeTag 或 ClassTag。

docs (see below) 中所述,您现在可以在隐式参数列表或上下文边界中使用它们来执行此类操作:-

import scala.reflect.runtime.universe._

def paramInfo[T: TypeTag](x: T): Unit = {
  val targs = typeOf[T] match { case TypeRef(_, _, args) => args }
  println(s"type of $x has type arguments $targs")
}

scala> paramInfo(42)
type of 42 has type arguments List()

scala> paramInfo(List(1, 2))
type of List(1, 2) has type arguments List(Int)

scala docs on Typetags

api docs