为什么 Scala 的不可变 Set 在其类型上不是协变的?
编辑:根据原始答案重写此问题
scala.collection.immutable.Set
类的类型参数不是协变的。 为什么是这样?
import scala.collection.immutable._
def foo(s: Set[CharSequence]): Unit = {
println(s)
}
def bar(): Unit = {
val s: Set[String] = Set("Hello", "World");
foo(s); //DOES NOT COMPILE, regardless of whether type is declared
//explicitly in the val s declaration
}
EDIT: Re-written this question based on original answer
The scala.collection.immutable.Set
class is not covariant in its type parameter. Why is this?
import scala.collection.immutable._
def foo(s: Set[CharSequence]): Unit = {
println(s)
}
def bar(): Unit = {
val s: Set[String] = Set("Hello", "World");
foo(s); //DOES NOT COMPILE, regardless of whether type is declared
//explicitly in the val s declaration
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
由于集合背后的概念是函数,所以
Set
的类型参数是不变的。 以下签名应该稍微澄清一下事情:如果
Set
在A
中是协变的,则apply
方法将无法采用类型的参数>A
由于函数的逆变性。Set
可能是A
中的逆变,但是当您想做这样的事情时,这也会导致问题:简而言之,最好的解决方案是保持事物不变,即使对于不可变的数据结构也是如此。 您会注意到
immutable.Map
的类型参数之一也是不变的。Set
is invariant in its type parameter because of the concept behind sets as functions. The following signatures should clarify things slightly:If
Set
were covariant inA
, theapply
method would be unable to take a parameter of typeA
due to the contravariance of functions.Set
could potentially be contravariant inA
, but this too causes issues when you want to do things like this:In short, the best solution is to keep things invariant, even for the immutable data structure. You'll notice that
immutable.Map
is also invariant in one of its type parameters.Martin Odersky 在 http://www.scala-lang.org/node/9764 中写道:
因此,我们为此构建原则性理由的所有努力似乎都被误导了:-)
at http://www.scala-lang.org/node/9764 Martin Odersky writes:
So, it seems that all of our efforts to construct a principled reason for this were misguided :-)
编辑:对于任何想知道为什么这个答案似乎有点偏离主题的人来说,这是因为我(提问者)修改了问题。
Scala 的类型推断足以确定在某些情况下您需要 CharSequences 而不是 Strings。 特别是,以下内容在 2.7.3 中对我有用:
至于如何直接创建 immutable.HashSets:不。 作为实现优化,少于 5 个元素的 immutable.HashSet 实际上并不是 immutable.HashSet 的实例。 它们是 EmptySet、Set1、Set2、Set3 或 Set4。 这些类是 immutable.Set 的子类,但不是 immutable.HashSet 的子类。
EDIT: for anyone wondering why this answer seems slightly off-topic, this is because I (the questioner) have modified the question.
Scala's type inference is good enough to figure out that you want CharSequences and not Strings in some situations. In particular, the following works for me in 2.7.3:
As to how to create immutable.HashSets directly: don't. As an implementation optimization, immutable.HashSets of less than 5 elements are not actually instances of immutable.HashSet. They are either EmptySet, Set1, Set2, Set3, or Set4. These classes subclass immutable.Set, but not immutable.HashSet.