Spec-Zone.ru › Kotlin 1.4

Перегрузка операторов

Kotlin позволяет нам предоставлять реализации для предопределённого набора операторов для наших типов. Эти операторы имеют фиксированное символьное представление (например, + или *) и фиксированный приоритет. Для реализации оператора мы предоставляем член-функцию или расширяющую функцию с фиксированным именем для соответствующего типа, т.е. типа левой части для бинарных операций и типа аргумента для унарных. Функции, перегружающие операторы, должны быть помечены модификатором operator.

Далее мы описываем соглашения, регулирующие перегрузку операторов для различных операторов.

Унарные операции

Унарные префиксные операторы

Выражение Переводится в
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()

Эта таблица показывает, что когда компилятор обрабатывает, например, выражение +a, он выполняет следующие шаги:

  • Определяет тип a, пусть это будет T;
  • Ищет функцию unaryPlus() с модификатором operator и без параметров для получателя T, т.е. член-функцию или расширяющую функцию;
  • Если функция отсутствует или неоднозначна, это ошибка компиляции;
  • Если функция присутствует и её тип возвращаемого значения R, то выражение +a имеет тип R;

Примечание, что эти операции, как и все остальные, оптимизированы для базовых типов и не вводят накладные расходы вызовов функций для них.

В качестве примера, вот как можно перегрузить унарный оператор минус:

data class Point(val x: Int, val y: Int)

operator fun Point.unaryMinus() = Point(-x, -y)

val point = Point(10, 20)

fun main() {
   println(-point)  // prints "Point(x=-10, y=-20)"
}

Инкременты и декременты

Выражение Переводится в
a++ a.inc() + см. ниже
a-- a.dec() + см. ниже

Функции inc() и dec() должны возвращать значение, которое будет присвоено переменной, к которой применялась операция ++ или --. Они не должны изменять объект, к которому применялась операция inc или dec.

Компилятор выполняет следующие шаги для разрешения оператора в постфиксной форме, например, a++.

  • Определяет тип a, пусть это будет T;
  • Ищет функцию inc() с модификатором operator и без параметров, применимую к получателю типа T;
  • Проверяет, что тип возвращаемого значения функции является подтипом T.

Эффект вычисления выражения:

  • Сохранить начальное значение a в временное хранилище a0;
  • Присвоить результат a0.inc() переменной a;
  • Вернуть a0 в качестве результата выражения.

Для a-- шаги полностью аналогичны.

Для префиксных форм ++a и --a разрешение работает аналогично, а эффект:

  • Присвоить результат a.inc() переменной a;
  • Вернуть новое значение a в качестве результата выражения.

Бинарные операции

Арифметические операторы

Выражение Переводится в
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.rem(b), a.mod(b) (устарело)
a..b a.rangeTo(b)

Для операций в этой таблице компилятор просто разрешает выражение в столбце «Переводится в».

Обратите внимание, что оператор rem поддерживается начиная с Kotlin 1.1. Kotlin 1.0 использует оператор mod, который устарел в Kotlin 1.1.

Пример

Ниже представлен пример класса Counter, который начинается с заданного значения и может быть инкрементирован с помощью перегруженного оператора +:

data class Counter(val dayIndex: Int) {
    operator fun plus(increment: Int): Counter {
        return Counter(dayIndex + increment)
    }
}

'In' оператор

Выражение Переводится в
a in b b.contains(a)
a !in b !b.contains(a)

Для in и !in процедура аналогична, но порядок аргументов изменён.

Оператор индексирования

Выражение Переводится в
a[i] a.get(i)
a[i, j] a.get(i, j)
a[i_1, ..., i_n] a.get(i_1, ..., i_n)
a[i] = b a.set(i, b)
a[i, j] = b a.set(i, j, b)
a[i_1, ..., i_n] = b a.set(i_1, ..., i_n, b)

Квадратные скобки переводятся в вызовы get и set с соответствующим числом аргументов.

Оператор вызова

Выражение Переводится в
a() a.invoke()
a(i) a.invoke(i)
a(i, j) a.invoke(i, j)
a(i_1, ..., i_n) a.invoke(i_1, ..., i_n)

Скобки переводятся в вызовы invoke с соответствующим числом аргументов.

Расширенные присваивания

Выражение Переводится в
a += b a.plusAssign(b)
a -= b a.minusAssign(b)
a *= b a.timesAssign(b)
a /= b a.divAssign(b)
a %= b a.remAssign(b), a.modAssign(b) (устарело)

Для операций присваивания, например, a += b, компилятор выполняет следующие шаги:

  • Если функция из правого столбца доступна
    • Если соответствующая двоичная функция (например, plus() для plusAssign()) также доступна, сообщить об ошибке (неопределённость),
    • Убедиться, что её тип возвращаемого значения Unit, и в противном случае сообщить об ошибке,
    • Сгенерировать код для a.plusAssign(b);
  • В противном случае, попробовать сгенерировать код для a = a + b (включая проверку типов: тип a + b должен быть подтипом a).

Примечание: присваивания — НЕ выражения в Kotlin.

Операторы равенства и неравенства

Выражение Переведено в
a == b a?.equals(b) ?: (b === null)
a != b !(a?.equals(b) ?: (b === null))

Эти операторы работают только с функцией equals(other: Any?): Boolean, которую можно переопределить для реализации пользовательской проверки равенства. Любая другая функция с таким же именем (например, equals(other: Foo)) не будет вызвана.

Примечание: === и !== (проверки тождества) не перегружаются, поэтому для них нет никаких соглашений.

Операция == является специальной: она переводится в сложное выражение, которое проверяет на наличие null. null == null всегда истинно, а x == null для непустого x всегда ложно и не вызовет x.equals().

Операторы сравнения

Выражение Переведено в
a > b a.compareTo(b) > 0
a < b a.compareTo(b) < 0
a >= b a.compareTo(b) >= 0
a <= b a.compareTo(b) <= 0

Все сравнения переводятся в вызовы compareTo, которые должны возвращать Int.

Операторы делегирования свойств

Функции-операторы provideDelegate, getValue и setValue описаны в Делегированные свойства.

Вызовы infix для именованных функций

Можно имитировать пользовательские infix-операции, используя вызовы infix-функций.

© 2010–2020 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/reference/operator-overloading.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API