在Scala中成功实现MapLike

时间:2014-05-27 19:26:07

标签: scala

我有一个时间的混蛋,在scala中实现了一个类型(为了我们的目的)[String,Set [Foo]],它为值中的Foos提供了额外的操作。实际实现比下面介绍的更复杂,但这是要点。我需要一个实现所有类似Map函数的类,并在作为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

1 个答案:

答案 0 :(得分:3)

+无法返回CustomMap,因为有时B1不会成为Set[Foo],而是Set[Foo]的其他超类型。这是您的错误的来源。 MapMapLike适用于提供地图实现的类,可以安全地为其添加任何值,并返回可用的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]]的子类型增加了额外的方法来处理多重映射 - 你可以根据需要做类似的事情。