奇怪的 Scala 元组行为

Tri*_*Nhu 3 scala

我注意到 Scala 中的这种行为

val list = List[(Int, Int)]()
val set = HashSet[(Int, Int)]()

scala> list :+ (1, 2)
res30: List[(Int, Int)] = List((1,2))

scala> list :+ (1 -> 2)
res31: List[(Int, Int)] = List((1,2))

scala> list :+ 1 -> 2
res32: List[(Int, Int)] = List((1,2))

//Work
// But the same for set not work
set += (1, 2)
<console>:14: error: type mismatch;
 found   : Int(2)
 required: (Int, Int)
       set += (1, 2)

//Ok may be += in set mean add all that mean this should work
set += ((1, 2))
set += ((1, 2), (3,4))
// Worked

// But why this one work
set += 1 -> 2
set += (1 -> 2)
set += ((1 -> 2))
Run Code Online (Sandbox Code Playgroud)

现在我很困惑,你能解释一下为什么元组不是元组吗?

scala> (4->5).getClass
res28: Class[_ <: (Int, Int)] = class scala.Tuple2

scala> (4,7).getClass
res29: Class[_ <: (Int, Int)] = class scala.Tuple2$mcII$sp
Run Code Online (Sandbox Code Playgroud)

gan*_*ter 5

我认为区别在于为HashSet[T]定义了两个重载+=,其中一个采用单个T,另一个采用多个(作为T*参数列表)。这是从 继承的Growable[T],并在此处显示

List[T].:+只能T在右手边取一个,这就是为什么编译器会发现它正在查看一个元组,而不是应该变成参数列表的东西。

如果你这样做,set += ((1, 2))它就会编译。还,val tuple = (1,2); set += x也有效。

请参阅 Mario Galic 的回答,了解为什么在HashSet[T].+=编译器的情况下选择无法输入的重载而不是可以输入的重载。


Mar*_*lic 5

解析器阶段-Xprint:parser给出

set.$plus$eq(1, 2)
Run Code Online (Sandbox Code Playgroud)

这似乎解决

def += (elem1: A, elem2: A, elems: A*)
Run Code Online (Sandbox Code Playgroud)

这是一种接受多个参数的方法,因此编译器可能会认为elem1 = 1elem2 = 2而不是将其视为(1,2)元组。

missingfaktor指向SLS 6.12.3 中缀操作作为解释

左关联运算符的右手操作数可能由括在括号中的几个参数组成,例如;op;(1,...,)。然后这个表达式被解释为 .op(1,...,)。

现在运算符+=是左结合的,因为它不以 结尾:,并且右边的操作数+=由括在括号 中的几个参数组成(1,2)。因此,通过设计,编译器不治疗(1,2)Tuple2