2011-09-17 10 views
9

PHP introduces a method that allows you to pick out all public values of an instance. ¿Hay alguna manera de hacer esto en Scala? Es decir, obtener todos los valores de todos los campos públicos de una clase instanciada (no objeto).Obteniendo los campos públicos (y sus respectivos valores) de una instancia en Scala/Java

Vamos a suponer de que tengo esta clase

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); 

Lo que necesito del método en cuestión, es conseguir un mapa o dos colecciones de valores.

var element.method          // the function I need 
ret: (("subject", "subject"), ("day", 1), ("time", 1)) // its output 

Respuesta

20

Es hora de dormir, por lo que no tiene tiempo para una respuesta completa, pero mira los resultados de element.getClass.getFields (o getDeclaredFields para campos privados) - se puede llamar getValue(element) sobre los objetos Field a buscar a sus valores.


despierto, y aún no hay una mejor respuesta, así:

En primer lugar, cabe destacar que en términos de Java, la clase no tiene un tema ámbito público, lo que tiene es un campo privado y sujeto Métodos de acceso subject() y subject_ $ eq (String).

Puede iterar sobre los objetos de campo privado como se describe anteriormente, poblando un mapa de los pares:

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 :_*) 
} 

Ahora podrá definir este método en TestElement (reemplazando o con this), o más generalmente útil definir una conversión de modo que usted puede llamar en cualquier getFields referencia

implicit def any2FieldValues[A](o: A) = new AnyRef { 
    def fieldValues = getFields(o) 
} 

Para que

element.fieldValues 

dará el resultado que desee.

+0

excelente, muchas gracias – sdkfasldf

+0

¿Qué hace la sintaxis ': _ *'? –

2

Puede hacer algo relativamente cerca de esta para las clases de casos:

case class SomeEntity(name : String, value : Int, misc : Boolean) 
val s = SomeEntity("Tom", 42, false) 
println(s.productIterator.map(_.toString).mkString(", ")) // "Tom, 42, false" 

... como era de esperar, itera productIterator más elementos de tipo Cualquier. Este método se genera automáticamente para las clases de casos solamente, y no recuperará el nombre del campo. Para cualquier otra cosa, necesitará usar la reflexión, y para eso, es posible que desee esperar a que salga 2.10.

+0

¿Qué cambios en 2.10? – sdkfasldf

3

A según la respuesta de Philippe, puede hacer esto para las clases de casos.

Más ampliamente, la misma técnica funciona para cualquier subclase de Product. Además de las clases de casos, las tuplas son otro ejemplo obvio, pero la lista es mucho más extensa que eso.

Echa un vistazo a las "subclases conocidas", aquí: http://www.scala-lang.org/api/current/scala/Product.html

1

Sólo una nota para aquellos que tratan de mejorar esta haciendo @duncan 's-tipo más fuerte enfoque:

En lugar de devolver una Map[String, Any], donde el valor se escribe como cualquier otro, que podría hacer lo siguiente:

def propertiesAsPairs() = { 
    val fields = (this.getClass.getDeclaredFields()) 
    for (field <- fields) yield { 
     field.setAccessible(true); 
     (field.getName, field.get(this)); 
    } 
} 
+0

¿Cuál es el tipo de devolución de esto? Me parece a Array [Pair [String, Any]], que no te ha comprado nada? –

0

Scala hace deliberadamente val, var y def comparten una interfaz común, por lo que puede repl ace los dos primeros con el último sin romper ningún código, sin siquiera requerir una recompilación.

Por lo tanto, si bien es posible hacer lo que quiera, daría lugar a un código quebradizo, que hace el tipo de cosas que no debería hacer.

+0

Creo que argumentaría que para clases de datos como esta, el punto es simplemente intercambiar valores en los campos. –

+0

aunque me haya sugerido que pregunte http://stackoverflow.com/q/7477248/97777 –

Cuestiones relacionadas