Set
定义为Set[A]
。它需要一个 in-variant 参数。由于我们正在传递共变量参数,因此按照预期工作:
scala> val a = Set(new Object)
a: scala.collection.immutable.Set[Object] = Set(java.lang.Object@118c38f)
scala> val b = Set("hi")
b: scala.collection.immutable.Set[String] = Set(hi)
scala> a & b
<console>:10: error: type mismatch;
found : scala.collection.immutable.Set[String]
required: scala.collection.GenSet[Object]
Note: String <: Object, but trait GenSet is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Object`. (SLS 3.2.10)
a & b
但下面有效:
scala> Set(new Object) & Set("hi")
res1: scala.collection.immutable.Set[Object] = Set()
在我看来,scala编译器会将Set("hi")
转换为Set[Object]
类型,因此可以正常工作。
这里做什么类型推理?有人可以链接到解释行为的规范,以及它何时发生?不应该为这种情况抛出编译时错误吗?作为同一操作类型的2个不同输出。
答案 0 :(得分:7)
不确定,但我认为您正在寻找的内容在the language spec下的“本地类型推断”中进行了描述(在本文编写时,第100页第6.26.4节)。
本地类型推断推断要传递给多态类型表达式的类型参数。假设 e 的类型为 [a 1 &gt;:L 1 &lt ;:U 1 , ..., n &gt;:Ln&lt ;:U n ] T 且没有明确的类型 参数给出。
本地类型推断将此表达式转换为类型应用程序 e [T 1 ,...,T n ] 。类型参数 T 1 ,...,T n 的选择取决于表达式出现的上下文和期望的类型 PT 。有三种情况。
[...]
如果表达式 e 显示为未应用于值参数的值,则通过求解约束系统来推断类型参数,该约束系统将表达式的类型 T 与预期类型 pt 。在不失一般性的情况下,我们可以假设 T 是一种值类型;如果它是方法类型,我们应用eta-expansion将其转换为函数类型。求解意味着为类型参数 a i 找到 T i 类型的替换σ >这样
推断类型 T i 均不是单身人士类型
尊重所有类型参数边界,即σL i &lt;:σa i 和σa i &lt ;:σU i i = 1,...,n 。
表达式的类型符合预期的类型,即σT&lt;:σpt。
如果不存在此类替换,则为编译时错误。如果存在多个替换,则本地类型推断将为每个类型变量选择 a i 最小或最大类型 T i 解决方案空间的em>。如果类型参数 a i 在类型中出现相反的变形,则将选择最大类型 T i T 表达式。在所有其他情况下将选择最小类型 T i ,即,如果变量在 T 类型中呈现共变,非变量或根本不存在。我们将这种替换称为给定约束系统的最佳解决方案,用于类型 T 。
简而言之:Scalac必须为您省略的泛型类型选择值,并在结果编译的约束条件下选择最具体的选择。
答案 1 :(得分:3)
表达式Set("hi")
可以是scala.collection.immutable.Set[String]
或scala.collection.immutable.Set[Object]
,具体取决于上下文的要求。 (当然,String
是有效的Object
。)当你写这个时:
Set(new Object) & Set("hi")
上下文需要Set[Object]
,因此这是推断的类型;但是当你这样写:
val b = Set("hi")
上下文未指定,因此选择了更具体的类型Set[String]
,这(如您所料)然后使a & b
生病。