2017-04-19 118 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