9

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

scala> var b = 2
b: 整数 = 2

斯卡拉> b += 1   

标量> b
res3: 整数 = 3

现在我将其纳入范围:

类 A(var x: Int) { def +=(y:Int) { this.x += y } }
隐式定义 int2A(i:Int) : A = new A(i)             

我正在定义一个新类和一个 += 操作,以及当我想将 Int 添加到 A 的 Int 值时的方便隐式转换。

当“A”类根本不是表达式的一部分时,我从没想过这会影响我的常规 Int 操作的行为方式。

但它确实:

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

斯卡拉> b += 1

标量> b  
res29: 整数 = 0

斯卡拉> b += 2

标量> b
res31: 整数 = 0

这里似乎发生的是 b:Int 被隐式转换为“A”,它没有绑定到任何变量,然后 += 被调用,丢弃结果。

Scala 似乎将隐式转换优先于已经定义给 Ints 的自然 += 行为(编译器魔术,而不是实际方法)。常识和 C++ 背景告诉我,只有在编译会失败的情况下,才应在不得已的情况下调用隐式函数。这导致了几个问题......

  • 为什么?这是一个错误吗?是设计使然吗?
  • 是否有解决方法(除了不为我的 DSL 的“+=”操作使用“+=”)?

谢谢

4

5 回答 5

15

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

鉴于 Scala 允许您定义 += 方法并允许您对变量执行 +=,我们是否可以更改两者的优先级?即首先尝试扩展+=,并且仅当搜索名为+=的方法失败时才尝试?

理论上是的,但我认为这会比目前的方案更糟糕。实际上,没有。Scala 的集合库中有许多类型定义了用于非破坏性添加的 + 方法和用于破坏性添加的 += 方法。如果我们改变了优先级,那么一个电话就像

  myHashTable += elem

会扩大到

  myHashTable = myHashTable + elem

所以它将构造一个新的哈希表并将其分配回变量,而不是简单地更新一个元素。不明智的做法...

于 2010-04-21T16:24:24.867 回答
6

来自Scala编程,第17章:

每当你写了 a += b 并且 a 不支持名为 += 的方法时,Scala 会尝试将它解释为 a = a + b。

Int类不包含方法+=。但是类A提供了+=方法。这可能会触发从Intto的隐式转换A

于 2010-04-21T13:26:01.070 回答
3

我不认为这是一个错误。实际上,Int 只有一个“+”方法,而没有一个“+=”方法。如果不存在具有“+=”方法的其他隐式,则 b += 1 将在编译时转换为 b = b + 1 。

于 2010-04-21T13:23:56.340 回答
1

Scala 似乎将隐式转换优先于+=已经定义为Ints 的自然转换。

你说的是哪个版本的 Scala?我不知道有任何版本+=Int. 当然,仍然支持的版本都没有,那一定是您那里拥有的一些非常古老的版本。

并且由于没有+=on Int,但是您正在调用on+=方法Int,因此 Scala 尝试通过隐式转换来满足该类型约束。

于 2010-04-21T14:01:01.340 回答
0

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

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

于 2010-04-21T13:35:50.110 回答