什么可能导致以下运算符重载以交换操作数?
What may have caused the following operator overloading to swap operands?
我正在使用 scala 语言定义 2 个运算符::++
和 ++:
,它们彼此完全相同:a :++ b == b ++: a
,它们显然不可交换:a :++ b != a ++: b
.
这是我用于测试的 Scala 代码:
import org.scalatest.FunSpec
import scala.collection.immutable.ListMap
case class Example(self: ListMap[String, String] = ListMap.empty) {
def :++(v: Example) = this.copy(
self ++ (v.self -- self.keys.toSeq)
)
def ++:(v: Example) = {
println("forward: " + :++(v))
println("reverse: " + (v :++ this))
v :++ this
}
}
class OperatorOverrideSuite extends FunSpec {
val p1 = Example(ListMap("a" -> "1"))
val p2 = Example(ListMap("a" -> "2"))
it(":++ operator should preserve first value") {
assert(p1 :++ p2 == p1)
}
it("++: operator should preserve second value") {
assert(p1 ++: p2 == p2)
}
}
第一个测试看起来一切正常,但是当 运行 我得到以下错误:
forward: Example(Map(a -> 2))
reverse: Example(Map(a -> 1))
Example(Map(a -> 1)) did not equal Example(Map(a -> 2))
ScalaTestFailureLocation: com.schedule1.datapassports.params.OperatorOverrideSuite$$anonfun at (OperatorOverrideSuite.scala:30)
Expected :Example(Map(a -> 2))
Actual :Example(Map(a -> 1))
<Click to see difference>
org.scalatest.exceptions.TestFailedException: Example(Map(a -> 1)) did not equal Example(Map(a -> 2))
at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:528)
at org.scalatest.FunSpec.newAssertionFailedException(FunSpec.scala:1630)
at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:501)
at ...
从打印的消息来看,scala 似乎覆盖了我的运算符并自行反转操作数,什么可能导致 scala 编译器以这种方式运行?这是一个错误吗?
我正在使用最新的 scala 2.11 和最新的 Java 8u181 进行测试。
来自Scala的语言specification:
The associativity of an operator is determined by the operator's last
character. Operators ending in a colon `:' are right-associative. All
other operators are left-associative.
这是一个演示:
scala> case class Test(name: String) {
| def ++:(that: Test) = println(s"Called ++: on $this with argument $that")
| def :++(that: Test) = println(s"Called :++ on $this with argument $that")
| }
defined class Test
scala> val (x, y) = (Test("x"), Test("y"))
x: Test = Test(x)
y: Test = Test(y)
scala> x ++: y
Called ++: on Test(y) with argument Test(x)
scala> x :++ y
Called :++ on Test(x) with argument Test(y)
因此,当您在代码中说 p1 ++: p2
时,执行的是 p2.++:(p1)
,相当于 p1 :++ p2
。这意味着您的两个运算符实际上是严格等价的。
我正在使用 scala 语言定义 2 个运算符::++
和 ++:
,它们彼此完全相同:a :++ b == b ++: a
,它们显然不可交换:a :++ b != a ++: b
.
这是我用于测试的 Scala 代码:
import org.scalatest.FunSpec
import scala.collection.immutable.ListMap
case class Example(self: ListMap[String, String] = ListMap.empty) {
def :++(v: Example) = this.copy(
self ++ (v.self -- self.keys.toSeq)
)
def ++:(v: Example) = {
println("forward: " + :++(v))
println("reverse: " + (v :++ this))
v :++ this
}
}
class OperatorOverrideSuite extends FunSpec {
val p1 = Example(ListMap("a" -> "1"))
val p2 = Example(ListMap("a" -> "2"))
it(":++ operator should preserve first value") {
assert(p1 :++ p2 == p1)
}
it("++: operator should preserve second value") {
assert(p1 ++: p2 == p2)
}
}
第一个测试看起来一切正常,但是当 运行 我得到以下错误:
forward: Example(Map(a -> 2))
reverse: Example(Map(a -> 1))
Example(Map(a -> 1)) did not equal Example(Map(a -> 2))
ScalaTestFailureLocation: com.schedule1.datapassports.params.OperatorOverrideSuite$$anonfun at (OperatorOverrideSuite.scala:30)
Expected :Example(Map(a -> 2))
Actual :Example(Map(a -> 1))
<Click to see difference>
org.scalatest.exceptions.TestFailedException: Example(Map(a -> 1)) did not equal Example(Map(a -> 2))
at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:528)
at org.scalatest.FunSpec.newAssertionFailedException(FunSpec.scala:1630)
at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:501)
at ...
从打印的消息来看,scala 似乎覆盖了我的运算符并自行反转操作数,什么可能导致 scala 编译器以这种方式运行?这是一个错误吗?
我正在使用最新的 scala 2.11 和最新的 Java 8u181 进行测试。
来自Scala的语言specification:
The associativity of an operator is determined by the operator's last character. Operators ending in a colon `:' are right-associative. All other operators are left-associative.
这是一个演示:
scala> case class Test(name: String) {
| def ++:(that: Test) = println(s"Called ++: on $this with argument $that")
| def :++(that: Test) = println(s"Called :++ on $this with argument $that")
| }
defined class Test
scala> val (x, y) = (Test("x"), Test("y"))
x: Test = Test(x)
y: Test = Test(y)
scala> x ++: y
Called ++: on Test(y) with argument Test(x)
scala> x :++ y
Called :++ on Test(x) with argument Test(y)
因此,当您在代码中说 p1 ++: p2
时,执行的是 p2.++:(p1)
,相当于 p1 :++ p2
。这意味着您的两个运算符实际上是严格等价的。