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))