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

发布于 2024-08-30 09:11:43 字数 796 浏览 8 评论 0原文

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

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 时进行方便的隐式转换整数值。

当“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++ 背景告诉我,只有在万不得已时才应调用隐式,否则编译会失败。这引出了几个问题……

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

谢谢

This simple test, of course, works as expected:

scala> var b = 2
b: Int = 2

scala> b += 1   

scala> b
res3: Int = 3

Now I bring this into scope:

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

I'm defining a new class and a += operation on it, and a convenient implicit conversion for those times when I want to add an Int to A's Int value.

I never expected this would affect the way my regular Int operations behave, when the "A" class is not at all part of the expression.

But it does:

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

scala> b += 1

scala> b  
res29: Int = 0

scala> b += 2

scala> b
res31: Int = 0

What seems to be happening here is that the b:Int is implicitly converted to an "A", which is not bound to any variable, and then += is invoked on it, discarding the results.

Scala seems to give high precedence the implicit conversion over the natural += behavior (compiler magic, not an actual method) that is already defined to Ints. Common-sense as well as a C++ background tells me implicits should only be invoked as a last resort, when the compilation would otherwise fail. That leads to several questions...

  • Why? Is this a bug? Is it by design?
  • Is there a work-around (other than not using "+=" for my DSL's "+=" operation)?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

故人的歌 2024-09-06 09:11:43

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

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

理论上是的,但我认为这会比当前的计划更糟糕。实际上,不。 Scala 的集合库中有很多类型都定义了 + 方法
非破坏性加法和破坏性加法的 += 方法。如果我们切换了优先级,那么像这样的调用

  myHashTable += elem

将扩展为

  myHashTable = myHashTable + elem

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

As others have noted, Int cannot have a += "method", because Int is immutable. What happens instead is that x += 1 is treated as a short form for x = x + 1, but only if there is no
method called += that is defined on the type. So method resolution takes precedence.

Given that Scala lets you define += methods and also lets you do += on variables, could we have changed the priority of the two? I.e. try expanded += first and only if that fails search for a method named +=?

Theoretically yes, but I argue it would have been worse than the current scheme. Practically, no. There are many types in Scala's collection library that define both a + method for
non-destructive addition and a += method for destructive addition. If we had switched the priority around then a call like

  myHashTable += elem

would expand to

  myHashTable = myHashTable + elem

So it would construct a new hashtable and assign this back to the variable, instead of simply updating an element. Not a wise thing to do...

贱贱哒 2024-09-06 09:11:43

来自 Scala 编程,第 17 章:

每当你写 a += b,并且 a 确实如此
Scala 不支持名为 += 的方法
将尝试将其解释为 a = a + b。

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

From Programming in Scala, Chapter 17:

Whenever you write a += b, and a does
not support a method named +=, Scala
will try interpreting it as a = a + b.

The class Int does not contain method +=. However class A provides += method. That might be triggering the implicit conversion from Int to A.

千仐 2024-09-06 09:11:43

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

I don't think it is a bug.
Actually, Int only has a "+" method but doesn't have a "+=" method.
b += 1 would transform to b = b + 1 in compile time if there is not a other implicit which has a "+=" method exists.

几度春秋 2024-09-06 09:11:43

Scala 似乎比已经定义为 Ints 的自然 += 给予隐式转换更高的优先级。

你说的是哪个版本的 Scala?我不知道有任何版本在 Int 上有 += 方法。当然,仍然受支持的版本都没有这样做,那一定是您那里的某个真正古老版本。

由于 Int 上没有 +=,但您在 调用一个 += 方法Int,Scala 尝试通过隐式转换来满足该类型约束。

Scala seems to give high precedence the implicit conversion over the natural += that is already defined to Ints.

Which version of Scala are you talking about? I don't know of any version that has a += method on Int. Certainly, none of the still supported versions do, that must be some really ancient version you have there.

And since there is no += on Int, but you are calling a += method on Int, Scala tries to satisfy that type constraint via an implicit conversion.

橙味迷妹 2024-09-06 09:11:43

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

请通过发送电子邮件至 [email protected] 或访问 n4.nabble.com/Scala-User-f1934582.html。如果它是一个错误,那就是它会被注意到并修复的地方。

Even withstanding Eastsun's explanation, it seems like this is a bug, and it should try the b=b+1 transformation before trying an implicit conversion for +=.

Please ask this question to the scala-user email list by emailing [email protected] or by visiting n4.nabble.com/Scala-User-f1934582.html. If it's a bug, that's where it will be noticed and fixed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文