为什么此代码有效:"map.apply(1)+=3"
Why does this code do work: "map.apply(1)+=3"
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
导致编译错误,原因。
第二个和第三个代码是如何展开的?
运行 :replay -Xprint:typer
来自 Scala 控制台:
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))
编辑评论中问题的答案
If all three expansions are the same, why second and third causes a compilation error?
第二个和第三个:map.apply(1) += 3
和 (map.apply(1)).+=(3)
编译得很好,也是等价的。
我试图用我的答案来证明的是:map.apply(1) += 3
不会扩展到 map.apply(1) = map.apply(1) + 3
正如 @som-snytt 在第一部分中所解释的那样他的回答。
顺便说一句 map(1) = map(1) + 3
不会 扩展到 map.update(1, map(1) + 3)
如问题中所述。
我希望这能澄清我的回答。
更新规则为in the spec under assignments, and expansion of assignment operators here。
问题是为什么明确的 m.apply
不被视为 m()
用于更新规则。
两种形式应该是equivalent.
刚刚有人 debated update syntax with 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 chat 中的解释是,在这种情况下,编译器不需要足够聪明来将 m.apply(1)
识别为 m(1)
。毕竟,可能会出现歧义。如果 apply
是无参数的并且 returns 是具有 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
是否应该编译失败,为了对称?如果编译器更加努力地保留源表达式,它至少可以在这种情况下更加一致。
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>
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
导致编译错误,原因。
第二个和第三个代码是如何展开的?
运行 :replay -Xprint:typer
来自 Scala 控制台:
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))
编辑评论中问题的答案
If all three expansions are the same, why second and third causes a compilation error?
第二个和第三个:map.apply(1) += 3
和 (map.apply(1)).+=(3)
编译得很好,也是等价的。
我试图用我的答案来证明的是:map.apply(1) += 3
不会扩展到 map.apply(1) = map.apply(1) + 3
正如 @som-snytt 在第一部分中所解释的那样他的回答。
顺便说一句 map(1) = map(1) + 3
不会 扩展到 map.update(1, map(1) + 3)
如问题中所述。
我希望这能澄清我的回答。
更新规则为in the spec under assignments, and expansion of assignment operators here。
问题是为什么明确的 m.apply
不被视为 m()
用于更新规则。
两种形式应该是equivalent.
刚刚有人 debated update syntax with 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 chat 中的解释是,在这种情况下,编译器不需要足够聪明来将 m.apply(1)
识别为 m(1)
。毕竟,可能会出现歧义。如果 apply
是无参数的并且 returns 是具有 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
是否应该编译失败,为了对称?如果编译器更加努力地保留源表达式,它至少可以在这种情况下更加一致。
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>