2017-04-19 120 views
1

我试图创建一个特质,将提供在子类中添加抽象类型的名称的名称:获取抽象类型

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方法移动到子类。有人可以解释为什么以及是否有办法从子课程中完成此调用?

回答

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] 
} 
+0

感谢。这就说得通了。 – jamborta

+0

有没有什么方法可以从同一个特征中调用getType方法?我想在签名固定的方法中使用它,以便它需要传递隐式参数 – jamborta

+0

我不会马上看到方法。 –

0

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

docs (see below)描述你现在可以使用他们的Implicit PARAM列表或上下文范围做这样的事情: -

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