PHP引入了一个方法,该方法允许您挑选一个实例的所有公共值。在Scala中有什么办法做到这一点吗?即获取实例化类(不是对象)的所有公共字段的所有值。
假设我有这个类
class TestElement( datatype: Datatype, var subject: String, var day: Int, var time: Int )
extends DataElement( datatype: Datatype ) {
def to( group: Group ) = group.add( this );
}
var element = new TestElement( datatype, "subject", 1, 1 );
我需要从问题中的方法中获得一个Map或两个值的集合。
var element.method // the function I need
ret: ( ("subject", "subject"), ("day", 1), ("time", 1) ) // its output
是睡觉的时间了,所以我没有时间给出完整的答案,但是看看element.getClass.getFields
(或getDeclaredFields
私有字段)的结果-您可以在Field
对象上调用getValue(element)
来获取它们的值。
现在醒了,仍然没有更好的答案,所以:
首先,请注意,在Java术语中,您的类没有公共字段subject,它只有私有字段subject和访问器方法subject()和subject_$eq(String)。
您可以像上面描述的那样遍历私有字段对象,从对中填充一个Map:
def getFields(o: Any): Map[String, Any] = {
val fieldsAsPairs = for (field <- o.getClass.getDeclaredFields) yield {
field.setAccessible(true)
(field.getName, field.get(o))
}
Map(fieldsAsPairs :_*)
}
现在您可以在TestElement上定义这个方法(用this
替换o
),或者更一般地定义一个转换,这样您就可以在任何引用
implicit def any2FieldValues[A](o: A) = new AnyRef {
def fieldValues = getFields(o)
}
所以
element.fieldValues
根据Philippe的回答,您可以对case类执行此操作。
更广泛地说,同样的技术适用于Product
的任何子类。和case类一样,Tuples是另一个明显的例子,但该列表远不止于此。
看一下"已知子类",在这里:http://www.scala-lang.org/api/current/scala/Product.html
对于case类,你可以做一些类似的事情:
case class SomeEntity(name : String, value : Int, misc : Boolean)
val s = SomeEntity("Tom", 42, false)
println(s.productIterator.map(_.toString).mkString(", ")) // "Tom, 42, false"
…如您所料,productIterator迭代Any类型的元素。此方法仅为case类自动生成,您将不检索字段的名称。对于更多的内容,您将需要使用反射,为此,您可能希望等待2.10版本发布。
对于那些试图通过使@duncan的方法类型更强来改进这一点的人:
不返回值类型为Any的Map[String, Any]
,您可以这样做:
def propertiesAsPairs() = {
val fields = (this.getClass.getDeclaredFields())
for ( field <- fields ) yield {
field.setAccessible( true );
( field.getName, field.get( this ) );
}
}
Scala故意让val
、var
和def
共享一个公共接口,所以你可以用后者替换前两者,而不会破坏任何代码——甚至不需要重新编译。
所以,虽然可以做您想做的事情,但它会导致脆弱的代码,做一些它不应该做的事情。