Frage

Ich bin ein Neuling Scala mich so vergeben, wenn dies eine dumme Frage, aber hier geht ...

Stellen wünsche ich eine erweiterte Kartentyp zu schaffen, die zusätzliche Methoden enthält. Ich kann ein paar Möglichkeiten sehen, dies zu tun. Die erste mit der Zusammensetzung wäre:

class Path[V](val m: Map[V, Int]) {
  // Define my methods
}

Ein weiteres über Vererbung wäre, z.

class Path[V] extends Map[V, Int] {
// Define my methods
}

Schließlich habe ich auch die "Eigenschaft" Weg betrachtet, z.

trait Path[V] extends Map[V, Int] {
// Define my methods
}

Zusammensetzung ist ein wenig umständlich, weil man ständig das Ding im Inneren zu verweisen haben. Vererbung ist ein ziemlich natürliche, aber es gibt eine Falte für mich (mehr in einer Sekunde). Traits scheint wie eine wirklich elegante Weise, dies und mit dem „zu tun mit“ baut es ist wirklich schön, aber es hat auch ein Problem für mich.

Die Falten I in renne sind mit Methoden wie ++. Sie geben eine neue Karte. Also lassen Sie uns sagen, die „meine Methode“ nach oben Wünsche bezeichnet, etwas zu der Karte hinzuzufügen (nur ein Beispiel, ich weiß, dass die Karte bereits dies hat), z.

trait Path[V] extends Map[V,Int] {
    def addOne(v: V, i: Int): Path[V] = this + (v -> i)
}

Dies erzeugt einen Fehler, da der Rückgabetyp nicht Pfad ist [V]. Jetzt weiß ich, ich „mit“ auf eine neue Instanz verwenden, um den Pfad [V] Merkmal hinzuzufügen. Aber ich nicht kontrollieren den Bau der neuen Karte hier. Gibt es einen Weg, um den Pfad [V] Merkmal hinzufügen? Ich dachte an eine neue unveränderliche Karte erstellen, die im Vorhinein gefüllt wurden und dann auf einem „mit Pfad [V]“ etikettieren, aber es gibt keinen solchen Konstruktor ich verwenden kann, die Pre-besiedelte Karte zu erstellen.

Ich vermute, (obwohl ich habe es nicht bestätigt), dass ich ein ähnliches Problem Vererbung haben würde. Ich könnte eine neue Methode hinzufügen, um einen neuen Eintrag zu der Karte hinzuzufügen, aber ich würde nicht einen „Pfad [V]“ wieder das ist, was ich will. Der kompositorische Ansatz scheint der einzige Weg zu sein, hier zu gehen.

Ich hoffe, das ist klar. Kommentare?

War es hilfreich?

Lösung

Vielleicht ist der einfachste Weg, dies zu tun, ist das MapProxy Merkmal zu verwenden:

import collection._

class Path[V](val self: Map[V, Int]) extends MapProxy[V, Int] {
   // without the companion object below
   def addOne(v: V, i: Int): Path[V] = new Path(this + (v -> i))
   // with the companion object below
   def addOne(v: V, i: Int): Path[V] = this + (v -> i)
   // other methods
}

// this companion object is not strictly necessary, but is useful:
object Path {
   implicit def map2path[V](map: Map[V, Int]): Path[V] = new Path(map)
}

Damit entfällt die Ungeschicklichkeit mit dem kompositorischen Ansatz, indem Sie einen Path zu behandeln, als ob es sich um eine Map ist:

scala> new Path(Map("a" -> 1)) + ("b" -> 2)
res1: scala.collection.Map[java.lang.String,Int] = Map((a,1), (b,2))

scala> new Path(Map("a" -> 1)).get("a")
res2: Option[Int] = Some(1)

Wenn Sie die implizite Konvertierung von Map zu Path (definiert in der Path Begleitobjekt) umfassen, dann können Sie auch eine Map behandeln, als ob es sich um eine Path ist:

scala> Map("a" -> 1).addOne("b", 2)
res3: Path[java.lang.String] = Map((a,1), (b,2))

Es gibt ein ähnliches SeqProxy Merkmal Verhalten zu einem Seq hinzuzufügen.

Im allgemeineren Fall eine Lösung ist, die Zuhälter meiner Bibliothek Muster verwenden . Diese damit verbundene Frage hat ein Beispiel.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top