我正在尝试编写一个可以混合到案例类中的特征(在 Scala 2.8 中),允许在运行时检查其字段,以实现特定的调试目的。我想按照它们在源文件中声明的顺序返回它们,并且我想省略案例类中的任何其他字段。例如:

trait CaseClassReflector extends Product {

  def getFields: List[(String, Any)] = {
    var fieldValueToName: Map[Any, String] = Map()
    for (field <- getClass.getDeclaredFields) {
      field.setAccessible(true)
      fieldValueToName += (field.get(this) -> field.getName) 
    }
    productIterator.toList map { value => fieldValueToName(value) -> value }
  }

}

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

scala> val c = Colour(234, 123, 23)
c: Colour = Colour(234,123,23)

scala> val fields = c.getFields    
fields: List[(String, Any)] = List((red,234), (green,123), (blue,23))

上面的实现显然是有缺陷的,因为它通过这些字段上的值相等来猜测字段在产品中的位置与其名称之间的关系,因此以下内容将不起作用:

Colour(0, 0, 0).getFields

有什么办法可以实现这一点吗?

有帮助吗?

解决方案

在每个例子中,我看到的字段是按相反的顺序:在getFields数组中的最后一项是的情况下类中所列的第一个。如果你使用的情况下班“很好”,那么你就应该能够映射到productElement(n) getDeclaredFields()( getDeclaredFields.length-n-1)

但是,这是相当危险的,因为我不知道在坚持,它必须是这样的规范什么,如果重写的情况下类VAL,它甚至不会出现在getDeclaredFields(它“会出现在该超类的字段)。

您可能会改变你的代码来承担的事情是这样的,但检查getter方法使用该名称和productIterator返回相同的值,并抛出,如果他们不(一个例外,这意味着你实际上并不知道什么对应于什么)。

其他提示

看树干,你会发现这一点。听意见,这是不支持:但是因为我还需要那些名字......

/** private[scala] so nobody gets the idea this is a supported interface.
 */
private[scala] def caseParamNames(path: String): Option[List[String]] = {
  val (outer, inner) = (path indexOf '$') match {
    case -1   => (path, "")
    case x    => (path take x, path drop (x + 1))
  }

  for {
    clazz <- getSystemLoader.tryToLoadClass[AnyRef](outer)
    ssig <- ScalaSigParser.parse(clazz)
  }
  yield {
    val f: PartialFunction[Symbol, List[String]] =
      if (inner.isEmpty) {
        case x: MethodSymbol if x.isCaseAccessor && (x.name endsWith " ") => List(x.name dropRight 1)
      }
      else {
        case x: ClassSymbol if x.name == inner  =>
          val xs = x.children filter (child => child.isCaseAccessor && (child.name endsWith " "))
          xs.toList map (_.name dropRight 1)
      }

    (ssig.symbols partialMap f).flatten toList
  }
}

下面是一个简短和工作版本,基于上文

的例子
  trait CaseClassReflector extends Product {
    def getFields = getClass.getDeclaredFields.map(field => {
      field setAccessible true
      field.getName -> field.get(this)
    })
  }

您还可以使用 ProductCompletion 从解释器包获取案例类的属性名称和值:

import tools.nsc.interpreter.ProductCompletion

// get attribute names
new ProductCompletion(Colour(1, 2, 3)).caseNames
// returns: List(red, green, blue)

// get attribute values
new ProductCompletion(Colour(1, 2, 3)).caseFields

编辑:roland 和 virtualeyes 的提示

有必要包括 scalap 图书馆是 scala-lang 集合.

感谢您的提示,roland 和 virtualeyes。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top