Scala优先于隐式转换而不是"自然"操作......为什么?这是一个错误吗?或者我做错了什么?

Ale*_*x R 9 language-features scala scala-2.8

当然,这个简单的测试按预期工作:

scala> var b = 2
b: Int = 2

scala> b += 1   

scala> b
res3: Int = 3

现在我将其纳入范围:

class A(var x: Int) { def +=(y:Int) { this.x += y } }
implicit def int2A(i:Int) : A = new A(i)             

我正在定义一个新类和一个+ =操作,并且当我想要将Int添加到A的Int值时,这是一个方便的隐式转换.

当"A"类不是表达式的所有部分时,我从未想到这会影响我的常规Int操作的行为方式.

但它确实:

scala> var b:Int = 0
b: Int = 0

scala> b += 1

scala> b  
res29: Int = 0

scala> b += 2

scala> b
res31: Int = 0

这里似乎发生的是b:Int被隐式转换为"A",它不绑定到任何变量,然后在其上调用+ =,丢弃结果.

Scala似乎高度优先于已经定义为Ints的自然+ =行为(编译器魔法,而不是实际方法)的隐式转换.常识以及C++背景告诉我,只有在编译失败时才应该作为最后的手段调用implicits.这导致了几个问题......

  • 为什么?这是一个错误吗?它是按设计的吗?
  • 是否有解决办法(除了不使用"+ ="用于我的DSL的"+ ="操作)?

谢谢

Mar*_*sky 13

正如其他人所说,Int不能有+ ="方法",因为Int是不可变的.相反,x + = 1被视为x = x + 1的缩写形式,但前提是没有在类型上定义的名为+ =的方法.因此方法解析优先.

鉴于Scala允许您定义+ =方法并且还允许您对变量执行+ =,我们是否可以更改两者的优先级?即尝试扩展+ =第一,并且只有在无法搜索名为+ =的方法时?

理论上是的,但我认为它会比目前的方案更糟糕.实际上,没有.Scala的集合库中有许多类型,它们既定义了非破坏性加法的+方法,又定义了用于破坏性加法的+ =方法.如果我们已经切换了优先权,那么就像是

  myHashTable += elem

会扩大到

  myHashTable = myHashTable + elem

因此,它将构造一个新的哈希表并将其分配回变量,而不是简单地更新元素.不是明智之举......

  • 这会使事情进一步复杂化。它会使一类有用的重构失效,其中继承被视图取代。 (2认同)

mis*_*tor 6

从Scala编程,第17章:

每当你写一个+ = b,并且a不支持名为+ =的方法时,Scala会尝试将其解释为a = a + b.

Int类不包含方法+=.但是类A提供+=方法.这可能会触发隐式转换IntA.

  • @Alex如何在不可变类上实现`+ =`? (3认同)
  • @Alex 好吧,这就是正交性。C++ 有数以万计的“东西”,包括一个 `+=` 方法。Scala 没有 `+=` 方法、`-=` 方法、`::=` 方法、`&&=` 方法等。它只有一个特性,即上面的规则,它与其余的语言提供各种东西。这就是正交性的美妙之处。 (2认同)

Ken*_*oom 0

即使不顾 Eastsun 的解释,这似乎是一个错误,它应该b=b+1在尝试隐式转换之前尝试转换+=

请通过发送电子邮件至 scala-user@listes.epfl.ch 或访问 n4.nabble.com/Scala-User-f1934582.html 向 scala 用户电子邮件列表询问此问题。如果它是一个错误,那就是它会被注意到并修复的地方。