通过Reflection获取案例类的参数

Cor*_*ped 3 reflection scala introspection scala-2.10

作为Matt R问题的后续跟进 ,由于Scala 2.10已经出现了相当长的一段时间,因此提取案例类的字段和值的最佳方法是什么.举一个类似的例子:

case class Colour(red: Int, green: Int, blue: String) {
  val other: Int = 42
} 

val RBG = Colour(1,3,"isBlue")
Run Code Online (Sandbox Code Playgroud)

我想得到一个列表(或数组或任何迭代器),它将构造函数中声明的字段作为这样的元组值:

[(red, 1),(green, 3),(blue, "isBlue")]
Run Code Online (Sandbox Code Playgroud)

我知道网上有很多关于同一问题的例子,但正如我所说,我想知道什么是提取所需信息的最理想方式

0__*_*0__ 6

如果你使用Scala 2.10反射,这个答案是你需要的一半.它将为您提供案例类的方法符号,因此您知道参数的顺序和名称:

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)
Run Code Online (Sandbox Code Playgroud)

您可以调用.name.toString这些方法来获取相应的方法名称.

下一步是在给定实例上调用这些方法.你需要一个运行时镜像

val rm = runtimeMirror(getClass.getClassLoader)
Run Code Online (Sandbox Code Playgroud)

然后你可以"镜像"一个实际的实例:

val p  = Person("foo", 33)
val pr = rm.reflect(p)
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过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)
Run Code Online (Sandbox Code Playgroud)


Fáb*_*Dei 5

每个 case 对象都是一个产品,因此您可以使用迭代器来获取其所有参数的名称,并使用另一个迭代器来获取其所有参数的值:

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)
Run Code Online (Sandbox Code Playgroud)

通过产品我的意思是这两个笛卡尔积和的实例产品。这需要 Scala 2.13.0;尽管 Product 之前可用,但仅在 2.13.0 版本中添加了获取元素名称的迭代器。

请注意,不需要反射。