编辑:根据原始答案重写此问题
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
}
答案 0 :(得分:53)
Set
在其类型参数中是不变的,因为集合作为函数背后的概念。以下签名应略微澄清:
trait Set[A] extends (A=>Boolean) {
def apply(e: A): Boolean
}
如果Set
中的A
是协变的,由于函数的逆转,apply
方法将无法获取A
类型的参数。 Set
中的A
可能是逆变,但如果您想要执行以下操作,这也会导致问题:
def elements: Iterable[A]
简而言之,最好的解决方案是保持事物不变,即使对于不可变数据结构也是如此。您会注意到immutable.Map
在其中一个类型参数中也是不变的。
答案 1 :(得分:49)
在http://www.scala-lang.org/node/9764 Martin Odersky写道:
“关于集合的问题,我认为非差异也源于实现。常见集合实现为哈希表,它是密钥类型的非变量数组。我同意这是一个有点恼人的不规则性。”< / p>
因此,我们为构建原则性原因所做的所有努力似乎都是错误的: - )
答案 2 :(得分:5)
编辑:对于任何想知道为什么这个答案似乎有点偏离主题的人来说,这是因为我(提问者)修改了这个问题。
Scala的类型推断足以弄清楚在某些情况下你想要CharSequences而不是字符串。特别是,以下内容适用于2.7.3:
import scala.collections.immutable._
def findCharSequences(): Set[CharSequence] = Set("Hello", "World")
关于如何直接创建immutable.HashSet:不要。作为一个实现优化,少于5个元素的immutable.HashSets实际上不是immutable.HashSet的实例。它们是EmptySet,Set1,Set2,Set3或Set4。这些类是immutable.Set的子类,但不是immutable.HashSet。