为什么这段代码能够正常工作:“map.apply(1)+ = 3”

时间:2016-01-18 04:32:58

标签: scala scala-collections

val map = scala.collection.mutable.Map(1 -> 2)

map(1) += 3
map.apply(1) += 3
(map.apply(1)).+=(3)

我不明白为什么这些代码都编译得很好。

在第一种情况下,我认为代码已扩展为map(1) = map(1) + 3map.update(1, map(1) + 3)。 但在第二和第三种情况下, map.apply(1) = map.apply(1) + 3导致编译错误,原因。

第二和第三个代码如何扩展到?

3 个答案:

答案 0 :(得分:3)

从scala控制台运行:replay -Xprint:typer

1)map(1) += 3扩展为:

map.update(1, map.apply(1).+(3))

2)map.apply(1) += 3扩展为:

map.update(1, map.apply(1).+(3))

3)(map.apply(1)).+=(3)扩展为:

map.update(1, map.apply(1).+(3))

编辑回答评论中的问题

  

如果所有三个扩展都相同,为什么第二个和第三个扩展会导致编译错误?

第二个和第三个:map.apply(1) += 3(map.apply(1)).+=(3)编译正常,也是等效的。

我试图用我的答案证明:map.apply(1) += 3没有扩展到map.apply(1) = map.apply(1) + 3 ,正如@ som-snytt在答案的第一部分所解释的那样。 /德尔>

BTW map(1) = map(1) + 3 不会扩展为map.update(1, map(1) + 3),如问题中所述。

我希望这能澄清我的答案。

答案 1 :(得分:2)

更新规则为in the spec under assignmentsassignment operators here扩展。

问题是为什么明确的m.apply不会被视为更新规则的m()

这两种形式应该是equivalent

有人debated仅使用examples更新语法。

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> val map = scala.collection.mutable.Map(1 -> 2)
map: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2)

scala> reify(map(1) += 3)
res0: reflect.runtime.universe.Expr[Unit] = Expr[Unit]($read.map.update(1, $read.map.apply(1).$plus(3)))

scala> reify(map.apply(1) += 3)
res1: reflect.runtime.universe.Expr[Unit] = Expr[Unit]($read.map.update(1, $read.map.apply(1).$plus(3)))

scala> reify(map(1) = map(1) + 3)
res2: reflect.runtime.universe.Expr[Unit] = Expr[Unit]($read.map.update(1, $read.map.apply(1).$plus(3)))

scala> reify(map.apply(1) = map.apply(1) + 3)
<console>:16: error: missing argument list for method apply in trait MapLike
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `apply _` or `apply(_)` instead of `apply`.
       reify(map.apply(1) = map.apply(1) + 3)
                 ^

scala> map.apply.update(1, map.apply(1) + 3)
<console>:16: error: missing argument list for method apply in trait MapLike
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `apply _` or `apply(_)` instead of `apply`.
       map.apply.update(1, map.apply(1) + 3)
           ^

编辑:FWIW,that's just how it is

编辑:

这是异常现象:

scala> val m = collection.mutable.Map(1->2)
m: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2)

scala> m(1) = m(1) + 3

scala> m(1) += 3

scala> m.apply(1) += 3

scala> m.apply(1) = m.apply(1) + 3
<console>:13: error: missing argument list for method apply in trait MapLike
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `apply _` or `apply(_)` instead of `apply`.
       m.apply(1) = m.apply(1) + 3
         ^

由于这些表达式都是等价的,因此它们都应该编译为update的调用。

最后一个表达式无法进行类型检查,因为编译器对m.apply.update(1, m.apply(1) + 3)进行机械重写而不是m.update

gitter聊天中的解释是,在这种情况下,编译器并不需要足够聪明才能将m.apply(1)识别为m(1)。毕竟,可能会出现含糊不清的情况。如果apply无参数且使用update方法返回值,该怎么办?只有在没有进行类型检查的情况下,您才将m.apply(1)作为m(1)吗?

很明显,根据规范,m(1) += ???已扩展为m(1) = m(1) + ???,然后转换为m.update(1, m(1) + ???)

在代码中,两个转换(将op=转换为x = x op exprx(1) = ???转换为x.update(1, ???))被压缩:

Deciding if something is mutable

On error with op=, attempt conversion to assignment

Converting to update(或简单分配)。

可能有可能解决实现中的限制,但它并不明显,它会很好地规范(如上所述,apply可能是无限制的。)

然后m.apply(1) += 3无法编译,对称性?如果编译器更加努力地保留源表达式,那么在这种情况下它至少可以更加一致。

答案 2 :(得分:0)

FWIW,这适用于2.12.0-M3

C:\Users\erichardson>scala
Welcome to Scala 2.12.0-M3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_66).
Type in expressions for evaluation. Or try :help.

scala>  val map = scala.collection.mutable.Map(1 -> 2)
map: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2)

scala>  map(1) += 3

scala> map
res1: scala.collection.mutable.Map[Int,Int] = Map(1 -> 5)

scala> map.apply(1) += 3

scala> map
res3: scala.collection.mutable.Map[Int,Int] = Map(1 -> 8)

scala> (map.apply(1)).+=(3)

scala> map
res5: scala.collection.mutable.Map[Int,Int] = Map(1 -> 11)

scala>