Scala: метод\перегрузка оператора
Следующий пример из книги "Программирование в Scala". Учитывая класс "Rational" и следующее определение метода:
def add(that: Rational): Rational =
new Rational(
this.numer * that.denom + that.numer * this.denom,
this.denom * that.denom
)
Я могу успешно перегрузить метод add с помощью удобной версии, которая принимает аргумент Int, а использует определение выше:
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))
^
Почему компилятор ищет унарную версию метода +?
Ответы
Ответ 1
В Scala любая конструкция типа +x, -x, ~x и !x преобразуется в вызов метода x.unary_+ и т.д. Это частично разрешает Java-подобный синтаксис имеющий !b как отрицание булева b, или -x как отрицание числа x.
Следовательно, фрагмент кода +(new Rational(that, 1)) переведен в (new Rational(that,1)).unary_+, а поскольку Rational не имеет этого метода, вы получаете ошибку компиляции. Вы получите эту ошибку, только если ваша функция называется +, -, ~ или !, так как они являются единственными символами Scala, которые можно использовать как унарные операторы. Например, если вы вызываете свою функцию @+, код компилируется просто отлично.
Хотя, я бы предложил написать переопределенную функцию add как:
def +(that: Int): Rational =
this + (new Rational(that, 1))
Этот код показывает намерение вашей функции лучше - вы добавляете новый Rational, построенный из целого числа в качестве числителя, и 1 в качестве знаменателя в this. Этот способ записи преобразуется в this.+(new Rational(that, 1)), что вам нужно - вызов функции + на this.
Обратите внимание, что вы можете использовать нотацию infix, но вызываемая функция. Например, если вы измените имя на add, вы все равно можете сохранить его как:
def add(that: Int): Rational =
this add (new Rational(that, 1))
Ответ 2
Если вы вызываете + с явным this, он должен работать
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 в вашем примере компилятор думает, что вы используете унарный оператор +, который не определен.
Ответ 3
Вы не указали оператор binary +, вы указали оператор унарного +.
Итак, вместо:
def +(that: Int): Rational =
+(new Rational(that, 1))
Вам нужно написать следующее:
def +(that: Int): Rational =
this +(new Rational(that, 1))