Spec-Zone.ru › Kotlin 1.7

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

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

Чтобы перегрузить оператор, пометьте соответствующую функцию модификатором operator:

interface IndexedContainer {
    operator fun get(index: Int)
}

При переопределении перегрузок вашего оператора, вы можете опустить operator:

class OrdersList: IndexedContainer {
    override fun get(index: Int) { /*...*/ }   
}

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

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

Выражение

Перевод

+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..b

a.rangeTo(b)

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

Ниже приведен пример 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 += b, компилятор выполняет следующие шаги:

  • Если функция из правого столбца доступна:

    • Если соответствующая бинарная функция (то есть plus() для plusAssign()) также доступна, a является изменяемой переменной, а возвращаемый тип plus является подтипом типа a, сообщить об ошибке (неопределённость).

    • Убедиться, что её возвращаемый тип является 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 функций.

Последнее изменение: 25 августа 2021
Встроенные функции Безопасные для типов билдеры

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

Spec-Zone.ru

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