【问题标题】:Getting the parameters of a case class through Reflection通过Reflection获取案例类的参数
【发布时间】:2013-12-26 07:43:12
【问题描述】:

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

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

【问题讨论】:

  • 因为案例类实现了 Product 特征,您应该能够使用 Product 方法:productIterator 与 zipwithindex 结合使用。

标签: scala reflection introspection scala-2.10


【解决方案1】:

如果您使用 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)

然后您可以使用reflectMethod 反映pr 每个方法并通过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)

【讨论】:

    【解决方案2】:

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

    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 版本中添加。

    请注意,不需要反射。

    【讨论】:

    • 如何获取类型?
    猜你喜欢
    • 1970-01-01
    • 2021-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多