在 Scala 中,假设我有一个这样的案例类:
case class Sample(myInt: Int, myString: String)
有没有办法让我获得
Seq[(String, Class[_])]
,或者更好,Seq[(String, Manifest)]
,描述案例类的参数?
最佳答案
我正在回答我自己的问题以提供基本解决方案,但我也在寻找替代方案和改进。
一种也与 Java 兼容且不限于 case 类的选项是使用 ParaNamer .在 Scala 中,另一种选择是解析 ScalaSig
附加到生成的类文件的字节。这两种解决方案都不适用于 REPL。
这是我从 ScalaSig
中提取字段名称的尝试(使用 scalap 和 Scala 2.8.1):
def valNames[C: ClassManifest]: Seq[(String, Class[_])] = {
val cls = classManifest[C].erasure
val ctors = cls.getConstructors
assert(ctors.size == 1, "Class " + cls.getName + " should have only one constructor")
val sig = ScalaSigParser.parse(cls).getOrElse(error("No ScalaSig for class " + cls.getName + ", make sure it is a top-level case class"))
val classSymbol = sig.parseEntry(0).asInstanceOf[ClassSymbol]
assert(classSymbol.isCase, "Class " + cls.getName + " is not a case class")
val tableSize = sig.table.size
val ctorIndex = (1 until tableSize).find { i =>
sig.parseEntry(i) match {
case m @ MethodSymbol(SymbolInfo("<init>", owner, _, _, _, _), _) => owner match {
case sym: SymbolInfoSymbol if sym.index == 0 => true
case _ => false
}
case _ => false
}
}.getOrElse(error("Cannot find constructor entry in ScalaSig for class " + cls.getName))
val paramsListBuilder = List.newBuilder[String]
for (i <- (ctorIndex + 1) until tableSize) {
sig.parseEntry(i) match {
case MethodSymbol(SymbolInfo(name, owner, _, _, _, _), _) => owner match {
case sym: SymbolInfoSymbol if sym.index == ctorIndex => paramsListBuilder += name
case _ =>
}
case _ =>
}
}
paramsListBuilder.result zip ctors(0).getParameterTypes
}
免责声明:我不太了解 ScalaSig 的结构,这应该被视为一种启发式方法。 特别是,此代码做出以下假设:
ClassSymbol
. MethodEntry
与姓名 <init>
其所有者的 ID 为 0。它会在嵌套的 case 类上失败(因为没有
ScalaSig
)。此方法也仅返回
Class
实例而不是 Manifest
s。请随时提出改进建议!
关于scala - 在 Scala 中,如何以编程方式确定案例类的字段名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6282464/