2012-10-09 17 views
11

Lassen Sie uns sagen, dass ich diese Klasse habenIn scala, wie Objekt Werte in Map [String, String] drehen?

case class Test (id: Long, name: String) 

und eine Instanz dieser Klasse:

Test : 
id -> 1 
name -> toto 

Ich möchte eine Karte [String, String] wie folgt erstellen:

Map("id" -> "1", "name" -> "toto") 

Meine Frage ist: Gibt es eine Möglichkeit, diese Instanz von Test in Map [String, String] zu verwandeln? Ich möchte ein Verfahren wie dieses zu verwenden, um zu vermeiden:

def createMap(instance: Test): Map[String, String] = { 
    val map = new Map[String, String] 
    map.put("id", instance.id.toString) 
    map.put("name", instance.name) 
    map 
} 

Wenn es keine Methode ist so in Scala zu tun, ist es eine Möglichkeit, über Klasseneigenschaften zu wiederholen? Vielleicht kann ich eine generische Funktion dazu erstellen:

Ist das möglich? Wenn Sie gute Beispiele/Links haben, bin ich interessiert.

+0

Antworten auf [diese Frage] (http://stackoverflow.com/questions/2224251/reflection-on-a-scala-case-class) kann helfen. – incrop

+0

Nicht, dass ich keine generischen Lösungen mag, aber für dieses Problem würde ich 'Map (" id "-> t.id.toString," name "-> t.name) verwenden, wobei" t "eine Instanz von ist "Test". – sschaef

+0

Vielen Dank für den Tipp! – alexgindre

Antwort

19

Ja, es ist möglich. Seit Scala 2.10 können Sie Reflektion verwenden.

Sie Unter der Annahme haben:

val test = Test(23423, "sdlkfjlsdk") 

Nachfolgend erhalten Sie, was Sie wollen:

import reflect.runtime.universe._ 
import reflect.runtime.currentMirror 

val r = currentMirror.reflect(test) 
r.symbol.typeSignature.members.toStream 
    .collect{case s : TermSymbol if !s.isMethod => r.reflectField(s)} 
    .map(r => r.symbol.name.toString.trim -> r.get.toString) 
    .toMap 

einfach um über Feldwerte von Fallklasse Verwendung .productIterator auf seine Instanz durchlaufen.

+0

Kann dieser Prozess umgekehrt werden? Von Karte zu Objekt? Wenn der vollständige Name der Klasse angegeben wird –

+1

@JeffLee Ja. Dies ist sowohl mit Reflektion als auch mit Makros möglich. Hier ist [ein Beispiel, das die Reflexion von Scala 2.10 verwendet] (https://github.com/sorm/sorm/blob/master/src/main/scala/sorm/reflection/Reflection.scala#L50-L58). –

10

Das Thema, mit dem Sie es zu tun haben, wird auf StackOverFlow unglaublich wiederkehrend und das Problem ist nicht trivial, wenn Sie eine typsichere Implementierung haben wollen.

Ein Weg, um das Problem zu lösen, ist die Verwendung von Reflexion (wie vorgeschlagen), aber ich persönlich bevorzuge die Verwendung des Typsystems und implicits.

Es gibt eine wohlbekannte Bibliothek, die von einem äußerst schlauen Typen entwickelt wurde, mit der Sie erweiterte Operationen ausführen können, z. B. jede Case-Klasse in eine typsichere heterogene Liste umwandeln oder heterogene Maps erstellen können Aufzeichnungen". Die Bibliothek wird Shapeless genannt, und hier ein Beispiel:

object RecordExamples extends App { 
    import shapeless._ 
    import HList._ 
    import Record._ 

    object author extends Field[String] { override def toString = "Author" } 
    object title extends Field[String] { override def toString = "Title" } 
    object id  extends Field[Int]  { override def toString = "ID" } 
    object price extends Field[Double] { override def toString = "Price" } 
    object inPrint extends Field[Boolean] { override def toString = "In print" } 

    def printBook[B <: HList](b : B)(implicit tl : ToList[B, (Field[_], Any)]) = { 
    b.toList foreach { case (field, value) => println(field+": "+value) } 
    println 
    } 

    val book = 
    (author -> "Benjamin Pierce") :: 
    (title -> "Types and Programming Languages") :: 
    (id  -> 262162091) :: 
    (price -> 44.11) :: 
    HNil 

    printBook(book) 

    // Read price field 
    val currentPrice = book.get(price) // Static type is Double 
    println("Current price is "+currentPrice) 
    println 

    // Update price field, relying on static type of currentPrice 
    val updated = book + (price -> (currentPrice+2.0)) 
    printBook(updated) 

    // Add a new field 
    val extended = updated + (inPrint -> true) 
    printBook(extended) 

    // Remove a field 
    val noId = extended - id 
    printBook(noId) 
} 

Buch verhält sich wie eine typsichere Karte, welche Objekte als Schlüssel verwendet indiziert können. Wenn Sie mehr wissen, interessiert sind, könnte ein guter Einstiegspunkt dieser Beitrag sein:

Are HLists nothing more than a convoluted way of writing tuples?

Verwandte Themen