2013-06-19 5 views
1

У меня проблемы с вложенными списками и отражением Scala.Scala Отражение вложенного списка

Как я могу исследовать поле класса case типа List[List[something]]?

Некоторые коды здесь. Он лишен - в реальной жизни он создает статические данные об отраженном классе. Интересная часть - inspectField.

import reflect.runtime.currentMirror 
import reflect.runtime.universe._ 

case class Pet(val name: String, val legs: Int) 
case class ListList2(val name: String, val stuff: List[List[Pet]]) 

object Boom extends App { 
    // Introspect class and find all its members (constructor fields) 
    val symbol = currentMirror.classSymbol(Class.forName("com.br.ListList2")) 
    val constructor = symbol.toType.members.collectFirst { 
     case method: MethodSymbol if method.isPrimaryConstructor && method.isPublic && !method.paramss.isEmpty && !method.paramss.head.isEmpty => method 
    }.getOrElse(throw new IllegalArgumentException("Case class must have at least 1 public constructor having more than 1 parameters.")) 

    // Loop through each field 
    constructor.paramss.head.map(c => inspectField(c)) 

    private def inspectField[T](sym:Symbol) : String = {  
     val cname = sym.name.toString 
     println("Field: "+cname) 
     val cType = sym.typeSignature 
     if(cType.typeSymbol.fullName.toString == "scala.collection.immutable.List") { 
      println("C: "+cType) 
      val subtype = cType.asInstanceOf[TypeRef].args(0) // Goes boom here on first recursive call 
      println("Sub:"+subtype) 
      inspectField(subtype.typeSymbol) 
     } 
     "Hi" 
    } 
} 

Мой случай класс определяет поле типа List[List[Animal]]. Я ожидаю, что мой код inspectField будет называться рекурсивно. Первый раз без проблем. Он печатает:

Field: name 
Field: stuff 
C: scala.List[scala.List[com.br.Pet]] 
Sub:scala.List[com.br.Pet] 

До сих пор это то, что я ожидаю. Теперь по рекурсивному вызову inspectField, на этот раз прохождение subtype первого звонка (List[Pet]). Я ожидал, что выход так:

Field: stuff 
C: scala.List[com.br.Pet] 
Sub:com.br.Pet 

Вместо этого идет бум с ошибкой, где отмечено:

Exception in thread "main" java.lang.ClassCastException: scala.reflect.internal.Types$PolyType cannot be cast to scala.reflect.api.Types$TypeRefApi 

ответ

1

Этот фрагмент кода показывает соответствие растащить тип, и два вызова showType показать, что вы» делать и что вы намерены.

val cType = sym.typeSignature 
def showType(t: Type): Unit = { 
    if(t.typeSymbol.fullName.toString == "scala.collection.immutable.List") { 
    t match { 
     case PolyType(typeParams, resultType) => 
     println(s"poly $typeParams, $resultType") 
     case TypeRef(pre, sym, args) => 
     println(s"typeref $pre, $sym, $args") 
     val subtype = args(0) 
     println("Sub:"+subtype) 
     showType(subtype.typeSymbol.typeSignature) 
     showType(subtype) 
    } 
    } 
} 
showType(cType) 
+0

Очень круто, спасибо! – Greg

Смежные вопросы