2012-04-13 12 views
2

UPDATE
die Antworten Alle hier gut sind, aber @ senia der tut dies die am unmittelbarsten, ohne dass zusätzliche Schritte. Dies führt möglicherweise zu Fehlern, aber wenn die Map [Symbol, T] -Konvention in Hunderten von Methoden verwendet wird, wird eine einstufige implizite Konvertierung vor der Kartenerstellung bevorzugt (Vermeidung des Symbol-Map-Schlüssel-Permgenspeichers). Jedenfalls, hier ist der Zuhälter:Scala Karte, implict Symbol Schlüssel zum String

class SymbolProvidesPair(i: Symbol) { def ->[T](s: T) = (i.toString.tail, s) } 
@inline implicit def symbol2String(i: Symbol) = new SymbolProvidesPair(i) 

Original-
Es stört mich ein bisschen String-Schlüssel in Maps, verlangsamt mich nur nach unten und ist, IMO, nicht als syntaktisch einfach auf die Augen als Symboltasten .

val map: Map[String, Int] = Map("strings" -> 1, "blow" -> 2) 
val map: Map[String, Int] = Map('symbols -> 1, 'rock -> 2) 

Also, habe ich eine implizite mein Juckreiz zu kratzen:

implicit def symbolKey2String[A <: Symbol, B](x:(A,B)) = (x._1.toString, x._2) 

Paar Dinge:
1) ist dies die korrekte Signatur? Das obige funktioniert, aber A <: Symbol Ich meine, etwas, das von Symbol gegenüber etwas abstammt, das Symbol entspricht.

2) Ich werde dies verwenden, wenn ich Maps manuell eintippe; d.h. nur zur Bequemlichkeit. Werde ich irgendwelche Haken mit diesem impliziten treffen? Es scheint Rand Case genug, um keine Probleme (wie String2Int, zum Beispiel) zu verursachen, aber nicht sicher, ob ich etwas vermisse.

Dank

EDIT
Ok, gut 1 # kann ich eigentlich nur sagen, was ich meine, [Symbol, B] statt [A <: Symbol, B]

Aber jetzt habe ich mich mit einem anderen Problem zu finden, das Symbol-to- string implizit bringt mich in eine Ecke der Art, wie ich dann Map [String, Type] für alle neuen Maps explizit definieren muss (dh die nette Compiler-Typ-Inferenz verlieren), um Symbol-Schlüssel verwenden zu können.

Wie dann, um das Beste aus beiden Welten zu bekommen, Kartensymbolschlüssel, aber mit abgeleiteten [String, Type], wenn nicht die Typ-Signatur angeben? das heißt, den Compiler schließen Karte haben [String, Int], wenn ich tun:

val map = Map('foo -> 1) 
+1

hmmm, ich denke, ich könnte einfach "Symbol" für "A" ersetzen ;-) – virtualeyes

+0

Diese Art von Verhalten könnte andere Entwickler überraschen. Vielleicht wäre es besser, '->' durch ein anderes Wort zu ersetzen? Zum Beispiel ': ->' oder '~>'. – senia

+0

Ich denke, im Zusammenhang mit Pimp-My-Library-Muster (das ist genau das Muster in Ihrer Antwort zur Verfügung gestellt), Symbol -> Typ ist völlig in Ordnung. Das Schöne am Scala-Compiler ist, dass jeder, der verwirrt ist, seine Maus über "->" bewegen kann, um durchzuklicken und das Implizite zu sehen. In Ruby, Groovy, etc., eher eine magische Mystery Tour ohne explizite Dokumentation. Außerdem nehmen Symbol Map-Schlüssel Permgen auf, so dass ihre augenscheinliche Verwendung einige Augenbrauen (und Untersuchung) aufwerfen sollte. Schließlich wird der Compiler Map [String, Type] ableiten, so dass auch einer herausfinden sollte, wie es passiert – virtualeyes

Antwort

2

Sie brauchen nicht explizit Karte des Typ angeben:

scala> class SymbolToPait(i: Symbol) { def ->[T](s: T) = (i.toString().tail, s)} 
defined class SymbolToPait 

scala> implicit def symbolToPair(i: Symbol) = new SymbolToPait(i) 
symbolToPair: (i: Symbol)SymbolToPait 

scala> 'Symbol -> "String" 
res0: (String, String) = (Symbol,String) 

scala> Map('Symbol -> "String") 
res1: scala.collection.immutable.Map[String,String] = Map(Symbol -> String) 

scala> Map('Symbol -> 1) 
res2: scala.collection.immutable.Map[String,Int] = Map(Symbol -> 1) 

Diese Art von Verhalten anderer Entwickler überraschen könnte. Vielleicht wäre es besser, -> durch ein anderes Wort zu ersetzen? Zum Beispiel :-> oder ~>.

+0

total krank, Alter ;-) pimp-my-library zu booten, also ist der Fall isoliert/sicher. Benutzt du das selbst oder hast es einfach ausgepeitscht? Irgendwelche Nachteile, auf die Sie achten sollten? – virtualeyes

+0

Ich lerne Scala für ungefähr 2 oder 3 Wochen, also habe ich noch keine Lieblingstricks. Und ich bin kein englischer Muttersprachler, daher fällt es mir schwer, einige Teile Ihres Kommentars zu verstehen. – senia

+0

Entschuldigung, "total krank, Alter" bedeutet so viel wie "Danke, große Antwort!" Ich habe das Muster implementiert, und in der Tat funktioniert der Compiler auf Symboltasten als Zeichenfolgen, ohne die Signatur angeben zu müssen. Beeindruckend, wenn Sie Scala für 2 oder 3 Wochen lernen, möchte ich sehen, wo Sie nach 1 Jahr sind ;-) – virtualeyes

2

Wie Sie notiert haben, besteht keine Notwendigkeit für A. Sie wollen wahrscheinlich auch das erste Zeichen fallen zu lassen, das ist immer ein '

ist
implicit def symbolKeyToString[B](x: (Symbol, B)) = (x._1.toString.tail, x._2) 

Was Tücken, na ja, müssen Sie jedes Mal, wenn die Signatur der Karte tippen und Ihre Schlüssel darf keine Leerzeichen enthalten oder Betreiberzeichen. Das würde ich nicht selbst tun ...

Edit: wenn Sie wollen, jedes Mal, wenn die Signatur nicht tippen, eine Alternative zu Map.apply verwenden und implicits vergessen:

object Map2 { 
    def apply[B](xs: (Symbol, B)*) = 
    xs map {case (k, v) => (k.toString.tail, v)} toMap 
} 
+0

+1, guter Punkt, wusste nicht, das 'wurde als Teil des Schlüssels erhalten! Das war das nächste Stück, wurde mir klar, oh nein, jetzt muss ich explizit die Kartensignatur eingeben, die den Zweck vereitelt. Wie auch immer, um den Compiler zu veranlassen, Map [String, Type] bei Verwendung von Symbolschlüsseln abzuleiten? – virtualeyes

+0

Interessant mit alternativer Map.apply. Das Schöne an pimp-my-library ist, dass ich das implizite in ein Paketobjekt fallen lassen kann und keinen Import durchführen muss. Außerdem sollte es völlig sicher sein (d. H.Ich habe nie die Absicht, Map [Symbol, Type] basierend auf dem permgen-Problem allein zu verwenden. – virtualeyes

+0

@virtualeyes Diese 'Map2' kann auch in Ihrem Paket definiert werden, das ist kein Nachteil bei der Verwendung von implicits. Mit @ senias Antwort überschreiben Sie ruhig das implizite 'any2ArrowAssoc' von Predef für Symbole, was zu Fehlern führen kann, wenn Sie es vergessen. –

1

Ich habe ein paar Warnungen über die aktuellen Lösungen.

Zunächst ändern Sie die Bedeutung von 'sym -> x, und es wird etwas anderes als ('sym, x) bedeuten. Ich würde das verwirrend finden.

Sie machen es auch schwierig, Code zu mischen, der diese Konvertierung mit Code verwendet, der tatsächlich Map[Symbol, _] benötigt.

Anstatt die Symbole in Zeichenfolgen zu konvertieren, bevor sie in eine Karte eingefügt werden, empfehle ich, die Karte einfach zu konvertieren. Scheint viel einfacher für mich.

scala> implicit def symMap2strMap[T](m: Map[Symbol, T]): Map[String, T] = m.map { 
    | case (key, value) => key.toString.tail -> value 
    | } 
symMap2strMap: [T](m: Map[Symbol,T])scala.collection.immutable.Map[String,T] 

scala> val sym = Map('foo -> 1, 'bar -> 2) 
sym: scala.collection.immutable.Map[Symbol,Int] = Map('foo -> 1, 'bar -> 2) 

scala> sym: Map[String, Int] 
res0: Map[String,Int] = Map(foo -> 1, bar -> 2) 

bearbeiten:

Sie sollten nie den Typ explizit zu konvertieren Map[Symbol, T] zu Map[String, T] angeben. Lassen Sie es einfach als Map[Symbol, T], bis Sie eine API treffen, die Zeichenfolgenschlüssel benötigt, dann lassen Sie Scala implizit in den gewünschten Typ konvertieren.

+0

guten Punkt, lassen Sie mich das ausprobieren, könnte der sicherste Ansatz sein ... – virtualeyes

+0

Whoops, Moment mal, das ist nicht was ich will ;-) Es ist wahrscheinlich ein kleines Problem, aber Map Symbol Schlüssel nehmen Permgen auf; @ senias Lösung macht die Konvertierung von Symbol in String vor (oder während) der Map-Erstellung, was Map [String, T] als Ergebnis ergibt. Außerdem möchte ich die Map-Post-Erstellung definitiv nicht manuell konvertieren. Ich werde Map [Symbol, T] Konvention in Hunderten von Controller-Methoden verwenden, wird mich verrückt machen, den "echten" Typ anzugeben. Kann gebissen werden, wahr, wir werden sehen, scheint viel mehr Fall casey als String2Int oder andere Guaranteed-Future-Bug – virtualeyes

+0

@virtualeyes Nicht sicher über die gesamte PermGen Problem. Sind die Symbole in PermGen gespeichert? Wie hilft die Konvertierung vor dem Einfügen in die Karte? Über die Angabe des realen Typs sollten Sie das nie tun müssen. Wird die Antwort aktualisieren. – leedm777