scala 获取抽象类型的名称

cl25kdpy  于 2023-10-18  发布在  Scala
关注(0)|答案(2)|浏览(142)

我试图创建一个trait,它将提供添加到子类中的抽象类型的名称:

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方法移到子类中,它就可以正常工作。有人能解释一下为什么以及是否有一种方法可以从子类进行此调用吗?

bjg7j2ky

bjg7j2ky1#

在你调用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]
}
ehxuflar

ehxuflar2#

请注意,以上的答案虽然不错,但在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文档

相关问题