如果地图只能为其值存储一个不变的类型,我无法弄清楚如何在不可变的地图中处理覆盖“+”。
类似的东西:
class FixedMap(val impl : Map[String, Int])
extends immutable.Map[String, Int] with immutable.MapLike[String, Int, FixedMap] {
// This should return FixedMap if B1 is Int, and Map[String,B1]
// if B1 is a superclass of Int; but there's no way to do that.
// It is possible to return FixedMap here but then you have to
// throw at runtime if B1 is not Int
override def +[B1 >: Int](kv : (String, B1)) : Map[String, B1] = {
kv match {
case (k, v : Int) =>
new FixedMap(impl + Pair(k, v))
case _ =>
impl + kv
}
}
// ...
}
我希望这可以像使用CanBuildFrom
的方法一样工作,并且如果可能的话始终保持原始类型。有办法吗?或者Map子类总是必须将值类型保留为类型参数吗?
这是一个完整的可编辑示例:
import scala.collection.immutable
// pointless class that wraps another map and adds one method
class FixedMap(val impl : Map[String, Int])
extends immutable.Map[String, Int] with immutable.MapLike[String, Int, FixedMap] {
override val empty : FixedMap = FixedMap.empty
// This should return FixedMap if B1 is Int, and Map[String,B1]
// if B1 is a superclass of Int; but there's no way to do that.
// It is possible to return FixedMap here but then you have to
// throw at runtime if B1 is not Int
override def +[B1 >: Int](kv : (String, B1)) : Map[String, B1] = {
kv match {
case (k, v : Int) =>
new FixedMap(impl + Pair(k, v))
case _ =>
impl + kv
}
}
override def -(key : String) : FixedMap = {
new FixedMap(impl - key)
}
override def get(key : String) : Option[Int] = {
impl.get(key)
}
override def iterator : Iterator[(String, Int)] = {
impl.iterator
}
def somethingOnlyPossibleOnFixedMap() = {
println("FixedMap says hi")
}
}
object FixedMap {
val empty : FixedMap = new FixedMap(Map.empty)
}
object TestIt {
val empty = FixedMap.empty
empty.somethingOnlyPossibleOnFixedMap()
val one = empty + Pair("a", 1)
// Can't do the below because one is a Map[String,Int] not a FixedMap
// one.somethingOnlyPossibleOnFixedMap()
}
答案 0 :(得分:2)
以下是我的尝试:
class FixedMap(val impl: immutable.Map[String, Int])
extends immutable.Map[String, Int] with immutable.MapLike[String, Int, FixedMap] {
override def +[B1 >: Int](kv: (String, B1)): immutable.Map[String, B1] = impl + kv
def +(kv: (String, Int))(implicit d: DummyImplicit): FixedMap = new FixedMap(impl + kv)
// ...
}
你是对的:你不能覆盖已经存在的+
,所以你必须把它留在那里 - 否则你的子类将无法做超类可以做的事情,这违反了{ {3}}。但是你可以添加一个额外的方法,你想要的确切参数(在这种特殊情况下你不需要CanBuildFrom
)。
唯一的问题是新方法与您尝试覆盖的方法具有完全相同的类型擦除,但具有不兼容的签名。要解决此问题,您可以将DummyImplicit
- 在Predef
中定义为一个隐式值始终可用的类。它的主要用途是在类似超载的情况下解决类型擦除问题。
请注意,要调用重载方法的地图的静态类型必须为FixedMap
才能生效。如果对象的运行时类型为FixedType
但是静态类型为常规Map[String, Int]
,则编译器将不会调用您的新重载方法。
答案 1 :(得分:1)
可以使用CanBuildFrom
实现您想要的功能。问题是 - 你真的想要/需要做到吗?在SO中有几个类似的问题,这里有一个(希望你能在那里找到答案):
通常,Scala会使用足够的工具来避免这种情况(扩展集合)。你真的需要一个很好的理由从这开始。
答案 2 :(得分:-1)
如果你添加另一个+重载,它看起来确实有效(我能说到目前为止最好):
def +(kv : (String, Int))(implicit bf : CanBuildFrom[FixedMap, (String, Int), FixedMap]) : FixedMap = {
val b = bf(empty)
b ++= this
b += kv
b.result
}
我之前看到的问题是由重写的+返回FixedMap引起的,从而阻止了对通用映射的任何升级。我想这允许该对的隐式转换为+'d工作。但是如果你修复了重写的+方法再次返回Map [String,B1],你就不能再对该对的值使用隐式转换了。编译器无法知道是否要转到超类映射,即Map [String,Any]或隐式转换为Int以便坚持使用FixedMap。有趣的是,方法的返回类型会改变是否使用隐式转换;我想给定一个FixedMap返回类型,编译器可以推断出B1总是只是B(或类似的东西!)。
无论如何这似乎是我的错误;你不能在pair._2上使用隐式转换,在与Map接口兼容的同时传递给+,甚至在概念上也是如此。现在我放弃了,我认为超载的+会正常工作。