2013-12-09 34 views
0

我有一個母特徵'合同',由許多案例類擴展,'scale'就是其中之一。我試圖做一個泛型函數,以便它接受這些案例類中的一個的對象,並根據它是什麼類型的對象來執行一些操作。這是部分代碼:製作通用功能並使用TypeOf

def getType[T: TypeTag](obj: T) = typeOf[T] 

def makeXMLElem[T <: Contract](contract: T): String = { 
     println(getType(contract)) 
     val symb = getType(contract).declaration(newTermName(name)).asTerm 
     val instanceMirror = runtimeMirror(contract.getClass.getClassLoader).reflect(contract) 
     val symbMirror = instanceMirror.reflectField(symb) 
     val symbValue = symbMirror.get 
     ....... 

現在,我嘗試通過「比例」並檢查其類型。 getType函數將其類型返回爲'Contract'而非'scale'。正如你能理解,我想訪問的情況下類「規模」的參數使用語句:

val symb = getType(contract).declaration(newTermName(name)).asTerm 

案例類「規模」具有以下特徵:

case class scale(amount:Int, currency:String) 

以來,該類型是被提取本身錯誤的,值「SYMB」不給任何價值,我得到以下運行時錯誤:

Caused by: scala.ScalaReflectionException: <none> is not a term 

如何使功能makeXMLElem更通用的無損耗Ø f關於'規模'的簽名或任何延伸'合同'的類別的信息?

回答

2

正如您從getType的定義中看到的那樣,typeOf[T]函數實際上並不關心您的值obj。它所做的只是編譯時的,給你一個T類型的具體表示。所以如果你有trait Foo; trait Bar extends Foo; getType[Foo](new Bar {}),你會得到Foo的類型信息而不是Bar。泛化泛型的全部要點是在編譯時保留必要的信息。

解決之道在於this answer:你必須通過getClass使用的contract運行時類和反映的結果。

def getType[T](clazz: Class[T])(implicit rm: ru.Mirror) = 
    rm.classSymbol(clazz).toType 

val symb = getType(contract.getClass) 

因此您的方法簽名可以簡化爲def makeXMLElem(contract: Constract)


實施例:

import reflect.runtime.{universe => ru} 
import ru._ 
implicit val rm = runtimeMirror(getClass.getClassLoader) 

trait Foo; case class Bar(baz: Int) extends Foo 

val b: Foo = Bar(33) 
b.getClass // Bar! 

val symb   = getType(b.getClass).declaration(newTermName("baz")).asTerm 
val instanceMirror = rm.reflect(b) 
val symbMirror  = instanceMirror.reflectField(symb) 
symbMirror.get // 33 !