Spec-Zone.ru › Kotlin 1.6

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

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-функций.

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

© 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