Domanda

Sto cercando di scrivere un tratto (in Scala 2.8) che possono essere mescolati per una classe case, consentendo ai suoi campi da ispezionare in fase di esecuzione, per un particolare scopo di debug. Voglio farli ritornare nell'ordine in cui sono state dichiarate nel file di origine, e vorrei omettere tutti gli altri campi all'interno della classe caso. Ad esempio:

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

È possibile che questo implementazione è chiaramente viziata perché indovina il rapporto tra la posizione di un campo nel prodotto e il suo nome dalla parità di valore su quelli di campo, in modo che la segue, per esempio, non funziona:

Colour(0, 0, 0).getFields

C'è un modo questo può essere realizzato?

È stato utile?

Soluzione

In tutti gli esempi che ho visto i campi sono in ordine inverso: l'ultimo elemento della matrice getFields è il primo elencato nella classe caso. Se si utilizzano classi case "bene", allora si dovrebbe solo essere in grado di mappare productElement(n) sul getDeclaredFields()( getDeclaredFields.length-n-1).

Ma questo è piuttosto pericoloso, come io non conosco nulla nelle specifiche che insiste sul fatto che si deve essere in questo modo, e se si ignora la val nella classe caso, non sarà nemmeno comparire in getDeclaredFields (esso 'll appaiono nei campi della superclasse che).

Si potrebbe modificare il codice di assumere le cose sono in questo modo, ma verificare che il metodo getter con quel nome e il productIterator restituiscono lo stesso valore e l'un'eccezione se non lo fanno (che significa che non si fa in realtà sa ciò che corrisponde a ciò che).

Altri suggerimenti

Cerca in tronco e troverete questo. Ascolta il commento, questo non è supportato: ma dato che ho anche bisogno di quei nomi ...

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

Ecco una versione corta e di lavoro, sulla base dell'esempio di cui sopra

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

È inoltre possibile utilizzare il ProductCompletion dal pacchetto interprete per arrivare ad attribuire nomi ei valori delle classi case:

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

Modifica: sentori di Roland e virtualeyes

E 'necessario includere la libreria scalap che fa parte della scala-Lang raccolta .

Grazie per il vostro suggerimenti, roland e virtualeyes.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top