Scala集合,不变类型发生了什么



在对一个scala应用程序进行重构时,我遇到了这样一种情况:从List到Set的更改产生了一个我以前没有遇到过的问题。我有一些关于方差的想法,但我想了解它对编译器到底意味着什么。

我有类似的东西,编译和工作都很好:

case class MyClassList(s: List[Any])
val myList = List(("this", false)) // List[(String, Boolean)]
val listWorks = MyClassList(myList)

然后我把列表改成:

case class MyClassSet(s: Set[Any])
val mySet = Set(("this", false)) // Set[(String, Boolean)]
val setFails = MyClassSet(mySet)
在这一点上,创建MyClassSet类型的对象不再允许我传递Set作为参数,即使它接受Any的Set。现在,当下面的工作(请注意,该集合与之前的mySet"相同")时,它有点令人困惑:
val setWorks1 = MyClassSet(Set(("this", false)))

我认为简单的解释是编译器将mySet val推断为Set[(String, Boolean)],但是当我在setWorks1的参数列表中直接实例化它时,因为它接受Set[Any],编译器将其推断为Set[Any]。这使得第一个示例失败,第二个示例通过。这些也可以工作,这表明前一个是正确的:

val setWorks2 = MyClassSet(mySet.toSet[Any])
val mySetOfAny: Set[Any] = Set(("this", false), ("that", true), ("other", false))
val setWorks3 = MyClassSet(mySetOfAny)

编译器显示的实际错误是:

Error:(15, 55) type mismatch;
found   : Set[(String, Boolean)]
required: Set[Any]
Note: (String, Boolean) <: Any, but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: (...)

list和set的定义如下:

type List[+A]  = scala.collection.immutable.List[A]
type Set[A]    = immutable.Set[A]
  • 是类型差异的差异,它允许我传递一个"比任何更受限制的类型"的列表作为参数,但在的情况下不是准备好了吗?
  • 这个区别只是阻止类型之间的强制转换吗?
  • 这主要是一个编译器的"限制"或一个不变类型的预期属性?
  • 在"实践"中,不变类型之间还有其他区别吗?或者它们归结为这样的类型转换吗?

1)解释如下:为什么scala的不可变集合的类型不是协变的?

基本上,Set[T]也是一个Function1[T, Boolean]Function1的签名是[-In, +Out],所以T不能同时是+T-T,因为scala不允许双方差(这会显著削弱类型系统)。

2)您可以使用.toSet[Any](这是asInstanceOf的包装器)轻松转换它。还有一种方法可以跳过方差检查。

3,4)这是泛型(多态)类型的预期性质。它们可以是不变的/协变的/逆变的(不只是)并且可以用简单的规则来正式描述。你可以在这里阅读解释:https://stackoverflow.com/a/27627891/1809978

相关内容

  • 没有找到相关文章

最新更新