获取抽象类型的名称

时间:2017-04-19 17:58:57

标签: scala traits type-systems

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

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

2 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

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

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

this.context.VotationOptions.AddWhere(option, vot => vot.Expiration < DateTime.Now);

请参阅scala docs on Typetags

请参阅api docs