6

我想从 Scala 的不可变 Map 派生。它是这样定义的:

trait Map[A, +B]

不幸的是,我的实现需要在 B 中保持不变。我尝试了以下方法,但没有成功:

def +(kv : (A, B)) : MyMap[A, B] = { ... }

override def +[B1 >: B](kv : (A, B1)) : MyMap[A, B1] =
    throw new IllegalArgumentException()

也许有一个技巧@uncheckedVariance

4

2 回答 2

3

问题是如果你从不可变映射派生一个不变的版本,你会破坏类型安全。例如:

val dm = DiotMap(1 -> "abc")
val m: Map[Int, Any] = dm

这个声明是有效的,因为Map它是协变的。如果您的集合无法处理协方差,当我使用 时会发生什么m

于 2011-08-17T23:09:01.800 回答
1

完全摆脱协方差当然是不合理的,也是不允许的。给定m: Map[A, String]v : Any,你可以做到val mm : Map[A, Any] = m + v。这就是Map定义所说的,所有实现者都必须遵循。您的类可能是不变的,但它必须实现 Map 的完整协变接口。

现在重新定义+抛出错误是一个不同的故事(还不是很健全)。您的新+方法的问题在于,在泛型擦除之后,它具有与其他+方法相同的签名。有一个技巧:添加隐式参数,使签名中有两个参数,这使得它与第一个不同。

def +(kv : (A,B))(implicit useless: A <:< A) : MyMap[A,B]

(只要找到一个隐式参数,您正在寻找什么并不重要。implicit useless: Ordering[String]同样有效)

这样做,您通常会遇到重载问题。如果在编译器不知道的情况下添加 B,则会调用失败的方法。在那里执行类型检查可能会更好,以便接受 B 实例。那将需要在您的地图中获得 Manifest[B] 。

于 2011-08-17T23:15:28.397 回答