为什么Scala的不可变Set在其类型中不协变?

时间:2009-03-24 09:11:01

标签: scala set covariance scala-collections

编辑:根据原始答案重写此问题

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
}

3 个答案:

答案 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。