为什么';scala编译器不能将其识别为元组吗?

为什么';scala编译器不能将其识别为元组吗?,scala,Scala,如果创建地图: val m = Map((4, 3)) 并尝试添加新的键值对: val m_prime = m + (1, 5) 我得到: error: type mismatch; found : Int(1) required: (Int, ?) val m_prime = m + (1, 5) 如果我这样做: val m_prime = m + ((1, 5)) 或: 然后它就起作用了。为什么编译器不接受第一个示例 我正在使用2.10.2,这确实很烦人(我经

如果创建地图:

val m = Map((4, 3))
并尝试添加新的键值对:

val m_prime = m + (1, 5)
我得到:

 error: type mismatch;
 found   : Int(1)
 required: (Int, ?)
       val m_prime = m + (1, 5)
如果我这样做:

val m_prime = m + ((1, 5))
或:

然后它就起作用了。为什么编译器不接受第一个示例


我正在使用2.10.2,这确实很烦人(我经常碰到这个)。首先,
+
方法来自一个通用的集合特性,只接受集合元素类型的一个参数
Map
的元素类型是成对的
(A,B)
。然而,Scala将这里的括号解释为方法调用括号,而不是元组构造函数。解释将在下一节中显示

要解决这个问题,您可以避免元组语法,而是使用箭头关联
key->value
,或者使用双括号,或者使用方法
updated
,它特定于
Map
updated
+
的作用相同,但将键和值作为单独的参数:

val m_prime = m updated (1, 5)

不过,Scala在这里失败的原因仍然不清楚,因为一般来说,中缀语法应该可以工作,而不需要括号。由于方法重载,这个特殊情况似乎被打破了:第二个
+
方法接受了数量可变的元组参数

演示:

trait Foo {
  def +(tup: (Int, Int)): Foo
}

def test1(f: Foo) = f + (1, 2)  // yes, it works!

trait Baz extends Foo {
  def +(tups: (Int, Int)*): Foo // overloaded
}

def test2(b: Baz) = b + (1, 2)  // boom. we broke it.

我的解释是,添加了vararg版本后,现在出现了一个歧义:is
(a,b)
a
Tuple2
或两个参数的列表
a
b
(即使
a
b
不是类型
Tuple2
,编译器可能会开始寻找隐式转换)。解决歧义的唯一方法是使用上述三种方法中的任何一种。

可能重复请参见,元组和参数列表之间存在相同的潜在歧义。@Gouraysama我认为这是相反的问题。是的,我刚刚意识到。公平地说,这是同一个编译器问题。它只是把peop弄糟了这是一个非常恼人的限制。一旦编译器发现可以用两个参数调用
+
,它就会去调用,并忘记元组的事情。然后它不进行类型检查,但它仍然停留在那里,不会返回尝试将其解释为元组。我猜这是因为元组/参数列表消歧发生得太早(可能是在解析过程中),无法作为类型检查的结果进行更改…实际上,这是一个更精确的演示。人们一直在问这个问题。
trait Foo {
  def +(tup: (Int, Int)): Foo
}

def test1(f: Foo) = f + (1, 2)  // yes, it works!

trait Baz extends Foo {
  def +(tups: (Int, Int)*): Foo // overloaded
}

def test2(b: Baz) = b + (1, 2)  // boom. we broke it.