[英]Extending a Scala collection
我想要一個試圖覆蓋現有密鑰值的Map。 我試過了:
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)
}
得到了:
<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)
^
我對Scala很陌生,無法找到解決這個問題的方法。 有幫助嗎? :)
編輯:我正在使用Scala 2.8.0.Beta1-prerelease(它對scala.collection進行了一些更改)
由於要覆蓋Map
方法,因此無法將特征定義為返回類型。
最簡單的解決方案是省略類型:
abstract override def + [B1 >: B] (kv: (A, B1)) = { /* ... */ }
// ...
abstract override def -(key: A) = super.-(key)
或者您可以明確並添加超類型:
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]
我認為你只需覆蓋+
,因為你的其他方法只委托給Map
。
這修復了你的編譯錯誤:
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)
}
但是,我認為你真的想裝飾collection.mutable.Map#+=
,如下:
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)
}
}
您可以使用帶有一點隱式魔法的scala.collection.immutable.Map來完成它。 也就是說,您在接口中定義了一個附加方法和一個隱式轉換。 這是我在2.7中的表現,我確定在2.8中有不同的方法可以覆蓋,但你應該得到一般的想法。
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
}
然后在伴隨對象中定義隱式:
object Unoverwriteable {
implicit def unoverwriteableMap[A, B](map0: scala.collection.immutable.Map[A, B]): Unoverwriteable[A, B] =
new Unoverwriteable[A, B] { def underlying = map0 }
}
要使用它,請向地圖添加Unwriteable類型注釋。 如果取消注釋main方法中的最后兩行,則會根據需要獲得KeyAlreadyExistsException。
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)
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.