Pregunta

Estoy tratando de escribir un rasgo (en Scala 2.8) que se pueden mezclar en una clase de caso, que permite a sus campos a ser inspeccionados en tiempo de ejecución, para un propósito particular, la depuración. Quiero llegar de nuevo en el orden en que fueron declarados en el archivo de origen, y me gustaría omitir cualquier otro campo dentro de la clase de caso. Por ejemplo:

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

La aplicación anterior es claramente erróneo porque adivina la relación entre la posición de un campo en el producto y su nombre por la igualdad del valor que en el campo, por lo que el siguiente, por ejemplo, no va a funcionar:

Colour(0, 0, 0).getFields

¿Hay alguna manera esto puede ser implementado?

¿Fue útil?

Solución

En todos los ejemplos que he visto los campos están en orden inverso: el último elemento de la matriz getFields es el primero de la lista en la clase de caso. Si utiliza clases de casos "muy bien", entonces sólo debe ser capaz de asignar productElement(n) en getDeclaredFields()( getDeclaredFields.length-n-1).

Sin embargo, esto es bastante peligroso, ya que no sé de nada en la especificación que insiste en que debe ser así, y si se reemplaza un val en la clase de caso, ni siquiera aparecerá en getDeclaredFields (se 'll aparecer en los campos de la superclase que).

Es posible cambiar el código para asumir las cosas son así, pero comprobar que el método getter con ese nombre y la productIterator devuelven el mismo valor y lanzar una excepción si no lo hacen (lo que significa que en realidad no se sabe lo que corresponde a lo que).

Otros consejos

Buscar en el tronco y encontrará esto. Escuchar el comentario, esto no es compatible: pero ya que también necesitaba esos nombres ...

/** 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
  }
}

Aquí hay una versión corta y de trabajo, basado en el ejemplo anterior

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

También puede utilizar el ProductCompletion del paquete intérprete para llegar a los nombres de atributos y valores de las clases de casos:

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

Editar: consejos de Roland y virtualeyes

Es necesario incluir la biblioteca scalap que es parte de la scala-lang colección .

Gracias por su consejos, Roland y virtualeyes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top