Следующий пример из книги, 'Программирующей в Scala'. Учитывая класс 'Рациональный' и следующее определение метода:
def add(that: Rational): Rational =
new Rational(
this.numer * that.denom + that.numer * this.denom,
this.denom * that.denom
)
Я могу успешно перегрузить добавить метод с версией удобства, которая берет Международный аргумент и использует определение выше:
def add(that: Int): Rational =
add(new Rational(that, 1))
Никакие проблемы до сих пор.
Теперь, если я изменяю имя метода на имя стиля оператора:
def +(that: Rational): Rational =
new Rational(
this.numer * that.denom + that.numer * this.denom,
this.denom * that.denom
)
И перегрузка как так:
def +(that: Int): Rational =
+(new Rational(that, 1))
Я получаю следующую ошибку компиляции:
(fragment of Rational.scala):19: error: value unary_+ is not a member of this.Rational
+(new Rational(that, 1))
^
Почему компилятор ищет унарную версию +
метод?
В Scala любая конструкция типа + x
, -x
, ~ x
и ! X
преобразуется в вызов метода x.unary _ +
и т. д. Это частично позволяет разрешить Java-подобный синтаксис наличия ! b
в качестве отрицания логического b
или -x
как отрицание числа x
.
Таким образом, фрагмент кода + (new Rational (that, 1))
транслируется в (new Rational (that, 1)). Unary _ +
и как ] Rational
не имеет этого метода, вы получите ошибку компиляции. Вы получите эту ошибку, только если ваша функция называется +
, -
, ~
или !
, поскольку это единственные символы, которые Scala допускает в качестве унарных операторов. Например, если вы вызвали свою функцию @ +
, код компилируется нормально.
Тем не менее, я бы посоветовал написать переопределенную функцию добавления как:
def +(that: Int): Rational =
this + (new Rational(that, 1))
Этот код лучше показывает назначение вашей функции - вы добавляете новый Rational
, построенный из целого числа в качестве числителя и ] 1
как знаменатель для это
. Этот способ записи переводится в this. + (New Rational (that, 1))
, что и нужно вам - вызов функции +
на this
].
Обратите внимание, что вы можете использовать инфиксную нотацию независимо от вызова функции. Например, если вы измените имя обратно на add
, вы все равно можете сохранить определение как:
def add(that: Int): Rational =
this add (new Rational(that, 1))
Если вызвать +
с явным этим
, то должно работать
def +(that: Int): Rational = this.+(new Rational(that, 1))
Scala позволяет определить одинарные операторы, которые могут быть использованы в префиксной нотации оператора. Например, можно использовать +
в качестве префиксного оператора для достижения того же самого:
def unary_+: Rational = this.+(new Rational(that, 1))
val a = new Rational(3,2)
val b = +a
Без явного this
в своем примере компилятор считает, что используется унарный оператор +
, который не определен.
Вы не указали двоичный оператор +, вы указали унарный оператор +.
Итак, вместо:
def +(that: Int): Rational =
+(new Rational(that, 1))
Надо написать следующее:
def +(that: Int): Rational =
this +(new Rational(that, 1))