我正在尝试编写一个特征(可以在Scala 2.8中使用),可以将其混入到case类中,以便在运行时检查其字段,以用于特定的调试目的。我想按在源文件中声明的顺序将它们取回,并且我想省略case类内的任何其他字段。例如:
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数组中的最后一项是case类中列出的第一项。如果您“很好”地使用案例类,那么您应该能够将productElement(n)
映射到getDeclaredFields()( getDeclaredFields.length-n-1)
上。
但这是相当危险的,因为我对规范中的任何内容都不知道必须坚持这种方式,并且如果您在case类中覆盖val,它甚至不会出现在getDeclaredFields中(它将出现在该父类(super class)的字段中)。
您可能会更改代码以假定事情是这样的,但是请检查具有该名称的getter方法和productIterator返回相同的值,如果不这样做,则抛出异常(这意味着您实际上并不知道对应于什么)什么)。