为什么 Scala 的不可变 Set 的类型不是协变的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/676615/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 16:19:48  来源:igfitidea点击:

Why is Scala's immutable Set not covariant in its type?

scalasetcovariancescala-collections

提问by oxbow_lakes

EDIT: Re-written this question based on original answer

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

The scala.collection.immutable.Setclass is not covariant in its type parameter. Why is this?

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
}

采纳答案by Daniel Spiewak

Setis invariant in its type parameter because of the concept behind sets as functions. The following signatures should clarify things slightly:

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

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

If Setwere covariant in A, the applymethod would be unable to take a parameter of type Adue to the contravariance of functions. Setcould potentially be contravariantin A, but this too causes issues when you want to do things like this:

如果Set是协变的A,则由于函数的逆变,该apply方法将无法采用类型参数ASet可能是逆变A,但是当您想要执行以下操作时,这也会导致问题:

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.Mapis also invariant in one of its type parameters.

简而言之,最好的解决方案是保持事物不变,即使对于不可变的数据结构也是如此。您会注意到immutable.Map它的类型参数之一也是不变的。

回答by Seth Tisue

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

http://www.scala-lang.org/node/9764Martin Odersky 写道:

"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 :-)

因此,似乎我们为此构建原则性原因的所有努力都被误导了:-)

回答by Jorge Ortiz

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:

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

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

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.

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