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))
^
Почему компилятор ищет унарную версию +
метод?
3 ответа
В 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
, Этот способ написания переводится на this.+(new Rational(that, 1))
то, что вы хотите - вызывая +
функция на this
,
Обратите внимание, что вы можете использовать инфиксную нотацию, однако функция вызывается. Например, если вы измените имя обратно на add
, вы все еще можете сохранить определение как:
def add(that: Int): Rational =
this add (new Rational(that, 1))
Если вы позвоните +
с явным 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
в вашем примере компилятор считает, что вы используете унарный оператор +
который не определен.
Вы не указали бинарный оператор +, вы указали унарный оператор +.
Так что вместо:
def +(that: Int): Rational =
+(new Rational(that, 1))
Вам нужно написать это:
def +(that: Int): Rational =
this +(new Rational(that, 1))