我正在尝试创建一个特征,它将提供在子类中添加的抽象类型的名称:
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$1: scala.reflect.ClassTag[T.this.T])Class[_].
Unspecified value parameter evidence$1.
myClassOf[T].getSimpleName
^
但是如果我将
getType
方法移动到子类中,它就可以正常工作。有人可以解释为什么以及是否有办法从子类进行此调用?
在调用
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
。由于它的返回类型是 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。
如文档中所述(见下文),您现在可以在隐式参数列表或上下文边界中使用它们来执行此类操作:-
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)
参见 api 文档