scala - 通过反射获取案例类的参数

标签 scala reflection introspection scala-2.10

作为后续
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")]

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

最佳答案

如果您使用 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 反射(reflection) 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)

关于scala - 通过反射获取案例类的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20466546/

相关文章:

scala - 从 Spark 中的多个 S3 存储桶中读取

scala - 将 1 个元素的列表转换为选项

scala - "dynamically"使用宏创建案例类

android - 我是否需要 root 权限才能访问内部类?

c# - 如何从其访问器中获取属性的唯一标识符

ruby - 为什么 Ruby 使用 respond_to?而不是responds_to?

scala - 使用 Actors 来开发内核

java - 获取泛型参数的泛型父类(super class)

java - 使用 Java 反射检索继承的属性名称/值

java - 如何正确使用Apache Common BeanUtil的BeanComparator来受益于内省(introspection)?