val map = scala.collection.mutable.Map(1 -> 2)
map(1) += 3
map.apply(1) += 3
(map.apply(1)).+=(3)
我不明白为什么这些代码都编译得很好。
在第一种情况下,我认为代码已扩展为map(1) = map(1) + 3
和map.update(1, map(1) + 3)
。
但在第二和第三种情况下,
map.apply(1) = map.apply(1) + 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 assignments,assignment operators here扩展。
问题是为什么明确的m.apply
不会被视为更新规则的m()
。
这两种形式应该是equivalent。
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 expr
和x(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>