Получить имя абстрактного типа

Я пытаюсь создать черту, которая будет предоставлять имя абстрактного типа, который добавляется в подкласс:

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 ответа

Решение

В тот момент, когда вы звоните 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)

смотрите scala документы на Typetags

см. API документы

Другие вопросы по тегам