我想从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
有一个技巧?
答案 0 :(得分:3)
问题在于,如果从不可变映射中派生出不变版本,则会破坏类型安全性。例如:
val dm = DiotMap(1 -> "abc")
val m: Map[Int, Any] = dm
此声明有效,因为Map
是协变的。如果您的收藏无法处理协方差,那么当我使用m
时会发生什么?
答案 1 :(得分: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实例。这需要在地图中获得清单[B]。