Этот простой тест, конечно, работает как ожидалось:
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)
Я определяю новый класс и + = операция на нем и удобное неявное преобразование в течение тех времен, когда я хочу добавить Интервал к Международному значению A.
Я никогда не ожидал, что это будет влиять на способ, которым ведут себя мои регулярные Международные операции, когда "A" класс нисколько не является частью выражения.
Но это делает:
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 должен только быть вызван как последнее прибежище, когда компиляция иначе перестала бы работать. Это приводит к нескольким вопросам...
Спасибо
Даже несмотря на объяснение Истсана, похоже, что это ошибка, и он должен попробовать преобразование b = b + 1
перед попыткой неявного преобразования для + =
.
Задайте этот вопрос списку рассылки пользователей scala по электронной почте (скрыто) или посетив n4.nabble.com/Scala-User-f1934582.html. Если это ошибка, ее заметят и исправят.
Как отмечали другие, Int не может иметь + = "метод", потому что Int неизменяем. Вместо этого происходит то, что x + = 1 рассматривается как краткая форма для x = x + 1, но только если нет метода с именем + =, который определен для типа. Таким образом, разрешение метода имеет приоритет.
Учитывая, что Scala позволяет вам определять методы + =, а также позволяет делать + = для переменных, можем ли мы изменить их приоритет? Т.е. сначала попробуйте расширенный + =, и только если это не поможет, найдите метод с именем + =?
Теоретически да, но я утверждаю, что это было бы хуже, чем текущая схема. Практически нет. В библиотеке коллекций Scala есть много типов, которые определяют как метод + для неразрушающего сложения , так и метод + = для деструктивного сложения. Если бы мы поменяли приоритет, вызов типа
myHashTable += elem
расширился бы до
myHashTable = myHashTable + elem
. Таким образом, он построил бы новую хеш-таблицу и присвоил ее обратно переменной, вместо простого обновления элемента. Не очень разумный поступок ...
Кажется, что Scala дает высокий приоритет неявному преобразованию над естественным
+ =
, которое уже определено дляИнт
с.
О какой версии Scala вы говорите? Я не знаю ни одной версии, в которой есть метод + =
в Int
. Конечно, ни одна из все еще поддерживаемых версий не поддерживает, это должна быть какая-то действительно древняя версия, которая у вас есть.
И поскольку нет + =
в Int
, но вы вызываете метод + =
в Int
, Scala пытается удовлетворить это ограничение типа с помощью неявного преобразования.
Из «Программирование на Scala», глава 17:
Когда вы пишете a + = b, а a не поддерживает метод с именем + =, Scala будет пытаться интерпретировать его как = а + б.
Класс Int не содержит метода + =
. Однако класс A
предоставляет метод + =
. Это могло вызвать неявное преобразование из Int
в A
.
Я не думаю, что это ошибка. На самом деле Int имеет только метод "+", но не имеет " + = "метод. b + = 1 преобразуется в b = b + 1 во время компиляции, если не существует другого неявного метода, имеющего метод" + = ".