嵌套列表的Scala反射

时间:2013-06-19 05:12:30

标签: list scala reflection nested

我在嵌套列表和Scala反射方面遇到了一些麻烦。

如何内省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"
    }
}

我的case类指定了List[List[Animal]]类型的字段。我希望我的inspectField代码可以递归调用。第一次没问题。它打印:

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

到目前为止,这是我的期望。现在递归调用inspectField,这次通过第一个电话subtype的{​​{1}}。我期待这样的输出:

(List[Pet])

相反,这会出现一个错误:“

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

1 个答案:

答案 0 :(得分: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)