我正在尝试编写一个特性(在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))
上面的实现显然是有缺陷的,因为它通过这些字段上的值的相等性来猜测字段在Product中的位置与其名称之间的关系,因此以下,例如,将不起作用:
Colour(0, 0, 0).getFields
有什么方法可以实现吗?
4 回答
在每个例子中,我看到字段的顺序是相反的:getFields数组中的最后一项是case类中列出的第一项 . 如果您使用案例类"nicely",那么您应该能够将
productElement(n)
映射到getDeclaredFields()( getDeclaredFields.length-n-1)
.但这是相当危险的,因为我不知道规范中有什么东西坚持它必须是这样的,如果你在case类中覆盖val,它甚至不会出现在getDeclaredFields中(它会出现在那个超类的领域) .
您可能会更改代码以假设事情是这样的,但检查具有该名称的getter方法和productIterator是否返回相同的值并抛出异常(如果它们没有)(这意味着您实际上并不知道对应的内容)什么) .
看看后备箱你会发现这个 . 听取评论,这是不支持的:但因为我也需要这些名字......
这是一个简短的工作版本,基于上面的例子
您还可以使用解释器包中的
ProductCompletion
来获取案例类的属性名称和值:Edit: hints by roland and virtualeyes
有必要包含
scalap
库,它是scala-lang collection的一部分 .感谢您的提示,roland和virtualeyes .