作为后续行动 Matt R's question,因为Scala 2.10已经出了很长一段时间,提取案例类的字段和值的最佳方法是什么。举一个类似的例子:
case class Colour(red: Int, green: Int, blue: String) {
val other: Int = 42
}
val RBG = Colour(1,3,"isBlue")
我想获得一个列表(或数组或任何迭代器),它将构造函数中声明的字段作为这样的元组值:
[(red, 1),(green, 3),(blue, "isBlue")]
我知道网上有很多关于同一问题的例子,但正如我所说,我想知道什么是提取所需信息的最理想方式
答案 0 :(得分:5)
如果您使用Scala 2.10反射,this answer是您需要的一半。它将为您提供案例类的方法符号,因此您知道参数的顺序和名称:
import scala.reflect.runtime.{universe => ru}
import ru._
def getCaseMethods[T: TypeTag] = typeOf[T].members.collect {
case m: MethodSymbol if m.isCaseAccessor => m
}.toList
case class Person(name: String, age: Int)
getCaseMethods[Person] // -> List(value age, value name)
您可以在这些方法上调用.name.toString
以获取相应的方法名称。
下一步是在给定实例上调用这些方法。你需要一个运行时镜像
val rm = runtimeMirror(getClass.getClassLoader)
然后你可以“镜像”一个实际的实例:
val p = Person("foo", 33)
val pr = rm.reflect(p)
然后,您可以使用pr
反映reflectMethod
每种方法,并通过apply
执行。如果不单独完成每个步骤,这里完全是一个解决方案(请参阅val value =
行了解提取参数值的机制):
def caseMap[T: TypeTag: reflect.ClassTag](instance: T): List[(String, Any)] = {
val im = rm.reflect(instance)
typeOf[T].members.collect {
case m: MethodSymbol if m.isCaseAccessor =>
val name = m.name.toString
val value = im.reflectMethod(m).apply()
(name, value)
} (collection.breakOut)
}
caseMap(p) // -> List(age -> 33, name -> foo)
答案 1 :(得分:1)
每个案例对象都是一个产品,因此可以使用迭代器获取其所有参数的名称,并使用另一个迭代器获取其所有参数的值:
case class Colour(red: Int, green: Int, blue: String) {
val other: Int = 42
}
val rgb = Colour(1, 3, "isBlue")
val names = rgb.productElementNames.toList // List(red, green, blue)
val values = rgb.productIterator.toList // List(1, 3, isBlue)
names.zip(values).foreach(print) // (red,1)(green,3)(blue,isBlue)
用 product 表示笛卡尔积和Product的实例。这需要Scala 2.13.0;尽管Product以前可用,但仅在版本2.13.0中添加了用于获取元素名称的迭代器。
请注意,不需要反射。