扩展 Scala 集合

发布于 2024-08-21 20:20:45 字数 1278 浏览 8 评论 0原文

我想要一个在尝试覆盖现有键的值时抛出的映射。我尝试过:

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 带来了一些变化)

I want a Map that throws on attempt to overwrite a value for existing key. I tried:

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)
}

and got:

<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)
                                                                           ^

I'm quite new to Scala and can't figure out a way to overcome this. Any help? :)

edit: I'm using Scala 2.8.0.Beta1-prerelease (which brings some changes to scala.collection)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

十二 2024-08-28 20:20:45

这修复了您的编译错误:

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)
  }
}

This fixed your compile error:

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)
}

However, I think you really want to decorate the collection.mutable.Map#+=, as follows:

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)
  }
}
陪你搞怪i 2024-08-28 20:20:45

当您重写 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

As you are overriding methods in Map, you can't define your trait as the return type.

The easiest solution is to just omit the types:

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

Or you could be explicit and add the super type:

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]

I think you would only have to override + though, as your other methods only delegate to Map.

江心雾 2024-08-28 20:20:45

您可以使用带有一点隐式魔法的 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 方法中的最后 2 行,您将根据需要得到 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)
   }
}

You can do it using a scala.collection.immutable.Map with a little implicit magic. That is, you define one additional method in the interface and an implicit conversion. Here's how I would do it in 2.7, I'm sure there's different methods to override in 2.8, but you should get the general idea.

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
}

Then you define the implicit in the companion object:

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

}

To use it add an Unwriteable type annotation to your map. If you uncomment the last 2 lines in the main method, you get a KeyAlreadyExistsException as desired.

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)
   }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文