&的奇怪行为功能集

时间:2013-08-03 05:45:21

标签: scala generics

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个不同输出。

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 。如果类型参数 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生病。