Scala Set,不变类型发生了什么?

标签 scala invariance

在 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 `_ <: (...)

列表和集合定义如下:

type List[+A]  = scala.collection.immutable.List[A]
type Set[A]    = immutable.Set[A]
  • 类型差异中的这种差异是否允许我传递“比 Any 更受限制的类型”的列表作为参数,但在以下情况下不能传递 a 设置?
  • 这种差异是否仅阻止类型之间的转换或转换?
  • 这主要是编译器“限制”还是不变类型的预期属性?
  • “在实践中”不变类型之间是否还有其他差异,或者它们是否归结为像这样的强制转换?

最佳答案

1) 解释如下: Why is Scala's immutable Set not covariant in its type?

基本上,Set[T] 也是一个Function1[T, Boolean]Function1 的签名是 [-In, +Out],因此 T 不能同时是 +T-T 同时,scala 不允许双变(它会显着削弱类型系统)。

2) 您可以使用 .toSet[Any](它是 asInstanceOf 的包装器)轻松转换它。还有一个办法skip variance check .

3, 4) 这是泛型(多态)类型的预期属性。它们可以是不变/协变/逆变(不仅如此),并且可以通过简单的规则进行正式描述。您可以在这里阅读说明:https://stackoverflow.com/a/27627891/1809978

关于Scala Set,不变类型发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40018193/

相关文章:

scala - 使用 Slick 1.0.0 计算行数

generics - Kotlin 泛型类属性

rust - 我如何处理 Rust 中的包装器类型不变性?

typescript - TypeScript 中的方差、协方差、逆变和协方差的区别

scala - 如何构建一个 Actor 及其包装器?

function - Scala:val foo = (arg: Type) => {...} 与 def(arg:Type) = {...}

scala - 依靠 Spark Dataframe 的速度非常慢

scala - 找不到用于排序的 Traverse Seq[ValidationNel[String, MyCaseClass]] => ValidationNel[String, Seq[MyCaseClass]]

c# - 无法在列表 C# 中保存通用接口(interface)实现