【问题标题】:Successfully implement MapLike in Scala在 Scala 中成功实现 MapLike
【发布时间】:2014-05-27 19:26:07
【问题描述】:

我有一段时间在 scala 中实现一个 Map 类型(为了我们的目的)[String, Set[Foo]],它为值中的 Foos 提供额外的操作。实际的实现比下面介绍的要复杂,但这是要点。我需要一个类来实现所有类似 Map 的函数,并在作为地图值的集合上提供额外的聚合。我见过的带有 MapLike 模式的扩展 Map,尤其是 this,不起作用。

到目前为止我得到了什么:

import scala.collection.{immutable, Map, MapLike}

class Foo(a:Int) 

class CustomMap
 (val underlying:Map[String,Set[Foo]] = Map[String,Set[Foo]]())
 extends Map[String, Set[Foo]] with MapLike[String, Set[Foo], CustomMap] {
  override def empty = new CustomMap(underlying.empty)

  def -(key: String) = new CustomMap(underlying - key)

  def +[B1 >: Set[Foo]](kv: (String, B1)): scala.collection.Map[String,B1] = new CustomMap(underlying + (kv._1 -> kv._2))

  def get(key: String): Option[Set[Foo]] = underlying.get(key)

  def iterator: Iterator[(String, Set[Foo])] = underlying.iterator

  override def size = underlying.size

  def getAllFoos() = underlying.values.flatten.toSet
}

val cm1:CustomMap = new CustomMap(Map("a" -> Set(new Foo(1))))
val cm2:CustomMap = cm1 + ("a" -> Set(new Foo(2)))
println(cm2.getAllFoos)

+ 方法和访问额外的聚合方法都存在问题。

任何指针?

file.scala:12: error: type mismatch;
 found   : B1
 required: Set[this.Foo]
  def +[B1 >: Set[Foo]](kv: (String, B1)): scala.collection.Map[String,B1] = new CustomMap(underlying + (kv._1 -> kv._2))
                                                                                                                     ^
file.scala:24: error: type mismatch;
 found   : scala.collection.Map[String,Set[this.Foo]]
 required: this.CustomMap
val cm2:CustomMap = cm1 + ("a" -> Set(new Foo(2)))
                        ^
two errors found

【问题讨论】:

    标签: scala


    【解决方案1】:

    + 不能返回CustomMap,因为有时B1 不是Set[Foo],而是Set[Foo] 的其他超类型。这是你错误的根源。 Map 和 MapLike 用于提供映射实现的类,该实现可以安全地添加任何值并返回可用的Map。所以Map[String, Set[Foo]] 总是可以有一个("", 5) 放入其中并成为Map[String, Any]。

    您可以通过使用“pimp-my-library”模式消除underlying 周围的包装,并避免这些问题:

    implicit class FooSetMap(val map: Map[String,Set[Foo]]) extends AnyVal {
      def getAllFoos = map.values.flatten.toSet
    }
    

    如果您愿意使用可变映射,请查看collection.mutable.MultiMap。这是一个 mixin 特征,它为 mutable.Map[A, mutable.Set[B]] 的子类型添加了额外的方法来处理多图 - 你可以根据你的需要做类似的事情。

    【讨论】:

    • 不幸的是,我们仍然支持 Scala 2.9,所以我无法访问隐式。我最终使用了您指出的 MultiMap 模式。在我们升级到 2.10 之前,它将一直有效。谢谢!
    • 隐式 pimp-my-library 模式仍然可以在 2.9 中完成,但不能使用值类 (extends AnyVal),您必须定义一个单独的 implicit def 而不是使用 implicit class。
    猜你喜欢
    • 2011-10-20
    • 2020-07-10
    • 2019-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多