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

发布于 2024-07-16 03:34:41 字数 423 浏览 4 评论 0原文

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

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夏至、离别 2024-07-23 03:34:41

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

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

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

def elements: Iterable[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:

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

If Set were covariant in A, the apply method would be unable to take a parameter of type A due to the contravariance of functions. Set could potentially be contravariant in A, but this too causes issues when you want to do things like this:

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.

何必那么矫情 2024-07-23 03:34:41

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

“关于集合的问题,我相信非方差也源于实现。常见的集合被实现为哈希表,它们是键类型的非变量数组。我同意这是一个有点烦人的不规则性。”< /p>

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

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

无边思念无边月 2024-07-23 03:34:41

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

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

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

至于如何直接创建 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:

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文