Scala括号语义

Scala括号语义,scala,Scala,当向映射追加值时,为什么Scala需要额外的括号块才能使该语句正常工作 不编译: vmap += (item.getName(), item.getString()) // compiler output: "found: String" 然而,这并不编译: vmap += ((item.getName(), item.getString())) // note the second set of enclosures 短暂性脑缺血发作 编辑:vmap定义为 val vmap = new m

当向映射追加值时,为什么Scala需要额外的括号块才能使该语句正常工作

不编译:

vmap += (item.getName(), item.getString()) // compiler output: "found: String"
然而,这并不编译:

vmap += ((item.getName(), item.getString())) // note the second set of enclosures
短暂性脑缺血发作

编辑:vmap定义为

val vmap = new mutable.HashMap[String, String]()
结语: 在本次编辑时,有两篇文章详细说明了两种可能的解释,这两种解释似乎都包含了对他们来说真实的因素。哪一个是正确的?我不能肯定地说……我只是一个还在学习语言的人。话虽如此,我已经改变了答案选择,因为我觉得一个答案(至少在某种程度上)包含在另一个答案中——所以我选择了更大的图景,因为我认为这将为其他人寻找答案提供更广泛的意义。具有讽刺意味的是,我试图更好地理解如何消除语言中的一些细微差别,而我逐渐意识到,这些差别比我想象的要多。我并不是说这是一件坏事——事实上(在我看来),这是任何灵活复杂的语言都应该具备的——但它确实会让一个人时不时地错过黑人/白人集会的世界……

为了结束这一过程,我们做了以下几点观察:
1) 选择的答案包含一个链接,链接到一个充满Scala brain benders的网站(我发现这对理解语言中前面提到的一些夸克非常有帮助)。强烈推荐。
2) 我确实遇到了另一个有趣的转折点——虽然单括号(上面的例子)不起作用,但在下面修改它,它就可以正常工作了

vmap += ("foo" -> "bar")

这可能与匹配方法/函数签名有关,但这只是我的猜测。

因为
Map+=
方法将
Tuple2[a,B]
作为参数

您必须用括号标记
Tuple2[A,B]
,否则编译器不会推断类型为
Tuple2

val x = (item.getName(), item.getString());//Tuple2[String, String]
vmap += x; // THIS COMPILES

vmap += (item.getName(), item.getString())// is identical to 
vmap += item.getName(), item.getString() // now it thinks you are adding a String, the result of item.getName()

vmap += (  (item.getName(), item.getString())   )// skips the first set, sees the Tuple, compiles.
A
Tuple2
是一对简单的A->B

val x = (5, 7); // the type is inferred to Tuple2[Int, Int];
Map
迭代使这一点更加明显:

map.foreach { case (key, value) => ...};

(key, value)// is a Tuple2
编译器将第一组圆括号视为无效/可跳过。 第二组圆括号创建所需的
Tuple2

val x = (item.getName(), item.getString());//Tuple2[String, String]
vmap += x; // THIS COMPILES

vmap += (item.getName(), item.getString())// is identical to 
vmap += item.getName(), item.getString() // now it thinks you are adding a String, the result of item.getName()

vmap += (  (item.getName(), item.getString())   )// skips the first set, sees the Tuple, compiles.
从SLS:

后缀运算符的优先级低于中缀运算符, 所以foo-bar-baz=foo.bar(baz)


在本例中:
vmap+=(item.getName(),item.getString());=vmap.+=(item.getName())

公认的答案实际上是错误的

没有为Map.+=获取元组的原因是,该方法使用第二个方法重载,该方法使用两个或多个参数

只有当参数的数量错误时,编译器才会尝试元组。但是如果你给它两个参数,并且有一个方法需要两个参数,这就是它所选择的,即使它不能进行类型检查

它不会开始尝试所有可能的组合,直到某些东西起作用,因为那将充满晦涩。(请参阅其。)

scala>def(p:Pair[String,Int])={val(s,i)=p;s.toInt+i}
f:(p:Pair[String,Int])Int
scala>f(“2”,3)//确定为元组
res0:Int=5
scala>trait F{def+=(p:Pair[String,Int])=F(p)}
定义性状F
scala>valfoo=newf{}
foo:F=$anon$1@6bc77f62
scala>foo+=(“2”,3)//确定为元组
res1:Int=5
scala>trait G{def+=(p:Pair[String,Int])=f(p);def+=(p:(String,Int),q:(String,Int),r:(String,Int)*=f(p)+f(q)+(r映射f).sum}
定义性状G
scala>val-goo=newg{}
goo:G=$anon$1@183aeac3
scala>goo+=(“2”,3)//对不起
:12:错误:类型不匹配;
找到:字符串(“2”)
必需:(字符串,Int)
goo+=(“2”,3)
^
scala>goo+=(((“2”,3),(“4”,5),(“6”,7))
res3:Int=27
我不能不提你和我的朋友,-Xlint,它会警告你arg的异常适应:

apm@mara:~/tmp$ skala -Xlint
Welcome to Scala version 2.11.0-20130811-132927-95a4d6e987 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def f(p: Pair[String, Int]) = { val (s,i) = p; s.toInt + i }
f: (p: Pair[String,Int])Int

scala> f("2",3)
<console>:9: warning: Adapting argument list by creating a 2-tuple: this may not be what you want.
        signature: f(p: Pair[String,Int]): Int
  given arguments: "2", 3
 after adaptation: f(("2", 3): (String, Int))
              f("2",3)
               ^
res0: Int = 5

scala> List(1).toSet()
<console>:8: warning: Adapting argument list by inserting (): this is unlikely to be what you want.
        signature: GenSetLike.apply(elem: A): Boolean
  given arguments: <none>
 after adaptation: GenSetLike((): Unit)
              List(1).toSet()
                           ^
res3: Boolean = false
apm@mara:~/tmp$skala-Xlint
欢迎使用Scala版本2.11.0-20130811-132927-95a4d6e987(OpenJDK 64位服务器虚拟机,Java 1.7.025)。
键入要计算的表达式。
键入:有关详细信息的帮助。
scala>def(p:Pair[String,Int])={val(s,i)=p;s.toInt+i}
f:(p:Pair[String,Int])Int
scala>f(“2”,3)
:9:警告:通过创建2元组调整参数列表:这可能不是您想要的。
签名:f(p:Pair[String,Int]):Int
给定参数:“2”,3
改编后:f((“2”,3):(字符串,Int))
f(“2”,3)
^
res0:Int=5
scala>List(1).toSet()
:8:警告:通过插入()调整参数列表:这不太可能是您想要的。
签名:GenSetLike.apply(elem:A):布尔
给定参数:
自适应后:类发电机(():单位)
列表(1).toSet()
^
res3:Boolean=false
关于适应的危险,请看,因为我们了解到,是否有帕伦基本上是风格的问题,当帕伦真正重要时,错误地使用它们会导致类型错误

在重载情况下调整元组:

scala> class Foo {
     | def f[A](a: A) = 1    // A can be (Int,Int,Int)
     | def f[A](a: A, a2: A) = 2
     | }
defined class Foo

scala> val foo = new Foo
foo: Foo = Foo@2645d22d

scala> foo.f(0,0,0)
<console>:10: warning: Adapting argument list by creating a 3-tuple: this may not be what you want.
        signature: Foo.f[A](a: A): Int
  given arguments: 0, 0, 0
 after adaptation: Foo.f((0, 0, 0): (Int, Int, Int))
              foo.f(0,0,0)
                   ^
res9: Int = 1
scala>class Foo{
|定义f[A](A:A)=1//A可以是(Int,Int,Int)
|定义f[A](A:A,a2:A)=2
| }
定义类Foo
scala>val foo=新foo
foo:foo=Foo@2645d22d
scala>foo.f(0,0,0)
:10:警告:通过创建3元组调整参数列表:这可能不是您想要的。
签名:Foo.f[A](A:A):Int
给定参数:0、0、0
适应后:Foo.f((0,0,0):(Int,Int,Int))
foo.f(0,0,0)
^
res9:Int=1

我的问题可能应该更清楚:我特别想理解的是,为什么您的第一个示例被推断为元组,而我的第一个示例被推断为简单字符串?我知道这是一个迂腐的问题,但Scala编译器如何/何时区分?例如,基于您的示例,为什么(5,7)不要求第二个括号是