2010-02-13 21 views
5

Ich möchte eine Map, die versucht, einen Wert für den vorhandenen Schlüssel zu überschreiben. Ich habe versucht:Erweitern einer Scala-Sammlung

trait Unoverwriteable[A, B] extends scala.collection.Map[A, B] { 
    case class KeyAlreadyExistsException(e: String) extends Exception(e) 

    abstract override def + [B1 >: B] (kv: (A, B1)): Unoverwriteable[A, B1] = { 
     if (this contains(kv _1)) throw new KeyAlreadyExistsException(
      "key already exists in WritableOnce map: %s".format((kv _1) toString) 
     ) 
     super.+(kv) 
    } 

    abstract override def get(key: A): Option[B] = super.get(key) 
    abstract override def iterator: Iterator[(A, B)] = super.iterator 
    abstract override def -(key: A): Unoverwriteable[A, B] = super.-(key) 
} 

und bekam:

<console>:11: error: type mismatch; 
found : scala.collection.Map[A,B1] 
required: Unoverwirteable[A,B1] 
       super.+(kv) 
        ^
<console>:16: error: type mismatch; 
found : scala.collection.Map[A,B] 
required: Unoverwirteable[A,B] 
      abstract override def -(key: A): Unoverwirteable[A, B] = super.-(key) 
                     ^

ich Scala ganz neu bin und kann nicht einen Weg finden, diese zu überwinden. Irgendeine Hilfe? :)

edit: Ich bin mit Scala 2.8.0.Beta1-Prerelease (die einige Änderungen an scala.collection bringt)

Antwort

4

Wie Sie Methoden zwingende in Map, können Sie Ihre Eigenschaft nicht definieren der Rückgabetyp

Die einfachste Lösung, um die Typen einfach weglassen ist:

abstract override def + [B1 >: B] (kv: (A, B1)) = { /* ... */ } 
// ... 
abstract override def -(key: A) = super.-(key) 

Oder Sie könnten die Super-Typ explizit und fügen Sie sein:

import scala.collection.Map 
abstract override def +[B1 >: B] (kv: (A, B1)): Map[A, B1] = { /* ... */ } 
// ... 
abstract override def -(key: A) = super.-(key): Map[A, B] 

Ich glaube, Sie würden nur + obwohl außer Kraft zu setzen haben, wie Ihre anderen Methoden nur an Map delegieren.

4

Dieser Fest Ihre Compiler-Fehler:

trait Unoverwriteable[A, B] extends scala.collection.Map[A, B] { 
    case class KeyAlreadyExistsException(e: String) extends Exception(e) 

    abstract override def + [B1 >: B] (kv: (A, B1)): scala.collection.Map[A, B1] = { 
     if (this contains(kv _1)) throw new KeyAlreadyExistsException(
      "key already exists in WritableOnce map: %s".format((kv _1) toString) 
     ) 
     super.+[B1](kv) 
    } 

    abstract override def get(key: A): Option[B] = super.get(key) 
    abstract override def iterator: Iterator[(A, B)] = super.iterator 
    abstract override def -(key: A): scala.collection.Map[A, B] = super.-(key) 
} 

Aber ich denke, Sie collection.mutable.Map#+= wirklich schmücken wollen, wie folgt:

trait Unoverwriteable[A, B] extends collection.mutable.Map[A, B] { 
    case class KeyAlreadyExistsException(e: String) extends Exception(e) 

    abstract override def +=(kv: (A, B)): this.type = { 
    if (this contains (kv _1)) 
     throw new KeyAlreadyExistsException("key already exists in WritableOnce map: %s".format((kv _1) toString)) 
    super.+=(kv) 
    } 
} 
+2

Im Fall ist es nicht klar, warum Sie erweitern möchten 'collection.mutable.Map', es ist, weil, wenn Sie eine unveränderliche Karte erweitern, jeder Aufruf von '+' gibt Ihnen einen _new map_. Da Sie die neue Karte mit einem Aufruf von super erstellen, ist diese neue Karte nicht überschreibbar! Es gibt zwei Möglichkeiten: überschreiben Sie alles nicht mit Aufrufen von Super, sondern mit Ihren eigenen Routinen, die ein altes unveränderbares nicht überschreibbares nehmen und ein neues mit dem neuen Element erstellen (falls erlaubt); oder verwenden Sie eine veränderbare Map und fügen Sie sie der gleichen Map hinzu, anstatt sie zu ersetzen. Letzteres ist viel weniger Arbeit. –

3

Sie eine scala.collection.immutable mit tun können .Karte mit ein wenig impliziter Magie. Das heißt, Sie definieren eine zusätzliche Methode in der Schnittstelle und eine implizite Konvertierung. Hier ist, wie ich es in 2.7 tun würde, ich bin sicher, es gibt verschiedene Methoden, um in 2.8 zu überschreiben, aber Sie sollten die allgemeine Idee bekommen.

trait Unoverwriteable[A, B] extends scala.collection.immutable.Map[A, B] { 
    import Unoverwriteable.unoverwriteableMap 

    case class KeyAlreadyExistsException(e: String) extends Exception(e) 

    def underlying: scala.collection.immutable.Map[A, B] 

    def update [B1 >: B] (key: A, value: B1): Unoverwriteable[A, B1] = { 
     if (this contains(key)) throw new KeyAlreadyExistsException(
      "key already exists in WritableOnce map: %s".format(key.toString) 
     ) 
     underlying update (key, value) 
    } 

    def get(key: A): Option[B] = underlying get key 
    def elements: Iterator[(A, B)] = underlying.elements 
    def -(key: A): Unoverwriteable[A,B] = underlying - key 
    def empty[C]: Unoverwriteable[A,C] = underlying.empty[C] 
    def size: Int = underlying.size 
} 

Dann definieren Sie die implizit in dem Begleitobjekt:

object Unoverwriteable { 
    implicit def unoverwriteableMap[A, B](map0: scala.collection.immutable.Map[A, B]): Unoverwriteable[A, B] = 
     new Unoverwriteable[A, B] { def underlying = map0 } 

} 

es verwenden, um eine Nicht Beschreibbar Typanmerkung zur Karte hinzufügen. Wenn Sie die letzten 2 Zeilen in der Hauptmethode auskommentieren, erhalten Sie eine KeyAlreadyExistsException wie gewünscht.

object UOMain { 
    def main(args: Array[String]): Unit = { 
     val map0 = Map((1 -> 1), (2 -> 2)): Unoverwriteable[Int, Int] 
     println("map0="+ map0) 

     val map1 = map0 - 2 
     println("map1="+ map1) 

     //val map2 = map1 + (1 -> 1000) 
     //println("map2" + map2) 
    } 
} 
Verwandte Themen