98

编辑:根据原始答案重新编写了这个问题

该类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
}
4

3 回答 3

57

Set由于集合作为函数背后的概念,它的类型参数是不变的。以下签名应该稍微澄清一下:

trait Set[A] extends (A=>Boolean) {
  def apply(e: A): Boolean
}

如果Set在 中是协变的,则由于函数的逆变性 A,该apply方法将无法采用类型参数。可能是逆变的,但是当你想做这样的事情时,这也会导致问题:ASetA

def elements: Iterable[A]

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.

于 2009-03-24T18:34:16.317 回答
53

at http://www.scala-lang.org/node/9764 Martin Odersky writes:

"On the issue of sets, I believe the non-variance stems also from the implementations. Common sets are implemented as hashtables, which are non-variant arrays of the key type. I agree it's a slightly annoying irregularity."

So, it seems that all of our efforts to construct a principled reason for this were misguided :-)

于 2011-05-31T04:49:17.753 回答
6

编辑:对于任何想知道为什么这个答案似乎有点偏离主题的人,这是因为我(提问者)已经修改了这个问题。

Scala 的类型推断足以确定在某些情况下您需要 CharSequences 而不是 Strings。特别是,以下在 2.7.3 中对我有用:

import scala.collections.immutable._
def findCharSequences(): Set[CharSequence] = Set("Hello", "World")

至于如何直接创建 immutable.HashSets:不要。作为实现优化,少于5个元素的immutable.HashSets实际上并不是immutable.HashSet的实例。它们是 EmptySet、Set1、Set2、Set3 或 Set4。这些类是 immutable.Set 的子类,但不是 immutable.HashSet。

于 2009-03-24T10:45:02.577 回答