Ich versuche, einen neuen Typ, Chunk, der eine Karte ähnelt zu implementieren. Grundsätzlich ist ein "Chunk" entweder ein Mapping von String -> Chunk oder eine Zeichenkette selbst.scala benutzerdefinierte Karte
ZB sollte es in der Lage sein, wie dies funktioniert:
val m = new Chunk("some sort of value") // value chunk
assert(m.getValue == "some sort of value")
val n = new Chunk("key" -> new Chunk("value"), // nested chunks
"key2" -> new Chunk("value2"))
assert(n("key").getValue == "value")
assert(n("key2").getValue == "value2")
Ich habe dies meistens arbeiten, mit der Ausnahme, dass ich bin ein wenig verwirrt durch, wie der Operator + für unveränderliche Karten funktioniert.
Hier ist, was ich habe jetzt:
class Chunk(_map: Map[String, Chunk], _value: Option[String]) extends Map[String, Chunk] {
def this(items: (String, Chunk)*) = this(items.toMap, None)
def this(k: String) = this(new HashMap[String, Chunk], Option(k))
def this(m: Map[String, Chunk]) = this(m, None)
def +[B1 >: Chunk](kv: (String, B1)) = throw new Exception(":(do not know how to make this work")
def -(k: String) = new Chunk(_map - k, _value)
def get(k: String) = _map.get(k)
def iterator = _map.iterator
def getValue = _value.get
def hasValue = _value.isDefined
override def toString() = {
if (hasValue) getValue
else "Chunk(" + (for ((k, v) <- this) yield k + " -> " + v.toString).mkString(", ") + ")"
}
def serialize: String = {
if (hasValue) getValue
else "{" + (for ((k, v) <- this) yield k + "=" + v.serialize).mkString("|") + "}"
}
}
object main extends App {
val m = new Chunk("message_info" -> new Chunk("message_type" -> new Chunk("boom")))
val n = m + ("c" -> new Chunk("boom2"))
}
Auch Kommentare, ob im allgemeinen diese Implementierung würde geschätzt angemessen ist.
Danke!
Edit: Die algebraische Datentypen Lösung ist ausgezeichnet, aber es bleibt ein Problem.
def +[B1 >: Chunk](kv: (String, B1)) = Chunk(m + kv) // compiler hates this
def -(k: String) = Chunk(m - k) // compiler is pretty satisfied with this
Der Operator - hier scheint zu funktionieren, aber der Operator + will, dass ich wirklich etwas vom Typ B1 zurückzukehren (glaube ich)? Es schlägt mit dem folgenden Problem:
overloaded method value apply with alternatives: (map: Map[String,Chunk])MapChunk <and> (elems: (String, Chunk)*)MapChunk cannot be applied to (scala.collection.immutable.Map[String,B1])
Edit2: Xiefei diese Frage beantwortet - Karte erstreckt erfordert, dass ich Griff + mit einem Supertyp (B1) von Chunk, so um dies zu tun, ich haben müssen einig Implementierung für das, so wird dies genügen:
def +[B1 >: Chunk](kv: (String, B1)) = m + kv
aber ich stattdessen nicht immer wirklich die Absicht, dass man zu verwenden, werde ich auch ist meine Implementierung, die ein Stück zurück, wie folgt:
def +(kv: (String, Chunk)):Chunk = Chunk(m + kv)
Die Implementierung für '+', im Falle von unveränderlichen Maps, muss eine neue Map mit dem hinzugefügten Schlüssel/Wert zurückgeben, richtig? Sie "wickeln" bereits eine Map ('_map'), so dass für eine Implementierung von' + 'nur das Delegieren zu' _map' funktioniert: 'def + [B1>: Chunk] (kv: (String, B1)) = _map + kv'. Das eigentliche Problem ist, dass dies für "einfache" Chunk's (die nur ein String sind) keinen Sinn macht. Mit anderen Worten, wenn Sie die oben beschriebenen Konstruktoren haben, bricht ** und ** das Implementieren von '+' Ihre Definition eines 'Chunk' ... ab, weil es einem String-Chunk erlaubt, // auch // Map zu werden- Stück. – Faiz