2013-12-09 2 views
0

У меня есть материнская черта «Контракт», которая распространяется на ряд классов дел, одним из которых является «масштаб». Я пытаюсь создать общую функцию таким образом, что она принимает объект одного из этих классов case и выполняет какое-то действие на основе того, что это за объект. Код:Создание общей функции и использование 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 возвращает свой тип как «Контракт», а не «масштаб». Как вы можете понять, что я пытаюсь получить доступ к параметрам на «шкале» случай класса с помощью оператора:

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 более общий характер без потери O f информацию о подписи «шкалы» или любого класса, который расширяет «Контракт», если на то пошло?

ответ

2

Как вы можете видеть из вашего определения getType, функция typeOf[T] фактически не заботится о вашей ценности obj. Все, что он делает, это во время компиляции, дайте вам подтвержденное представление типа T. Так что, если у вас есть trait Foo; trait Bar extends Foo; getType[Foo](new Bar {}), вы получите информацию о типе для Foo не Bar. Весь смысл редифицированных дженериков заключается в сохранении необходимой информации во время компиляции.

Решение заключается в this answer: Вы должны использовать класс выполнения из contract через getClass и отражают тот результат.

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 ! 
Смежные вопросы