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))
Другие вопросы по тегам