0Pricing
Kotlin Academy · Урок

Лучшие практики

Сохраняйте интуитивность операторов

«Лучшие практики» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.

Сохраняйте интуитивность операторов

Перегружайте оператор только тогда, когда его смысл очевиден. Оператор + для векторов понятен, а использование + в значении «отправить электронное письмо» — нет.

data class Vec(val x: Int, val y: Int) {
    operator fun plus(o: Vec) = Vec(x + o.x, y + o.y)
}

fun main() {
    println(Vec(1, 2) + Vec(3, 4))
}

Сохраняйте ожидаемую семантику

Соблюдайте привычные алгебраические свойства: для симметричных типов выражение a + b должно восприниматься как коммутативное и не удивлять читателей.

data class Money(val cents: Int) {
    operator fun plus(o: Money) = Money(cents + o.cents)
}

fun main() {
    println(Money(100) + Money(50))
}

Отдавайте предпочтение неизменяемости

Такие операторы, как plus, должны возвращать новое значение, а не изменять получатель, как это происходит с числами.

data class Point(val x: Int) {
    operator fun plus(o: Point) = Point(x + o.x)
}

fun main() {
    val a = Point(1)
    val b = a + Point(2)
    println("${a.x} ${b.x}")
}

plus и plusAssign

Определяйте plus для неизменяемых значений, а plusAssign — для изменения изменяемых контейнеров на месте. Не определяйте оба оператора с противоречащим друг другу поведением.

class Cart {
    val items = mutableListOf<String>()
    operator fun plusAssign(item: String) { items.add(item) }
}

fun main() {
    val c = Cart()
    c += "book"
    println(c.items)
}

Согласовывайте типы возвращаемых значений

Двоичные операторы должны возвращать тот же тип, чтобы результаты можно было естественно объединять в цепочки.

data class N(val v: Int) {
    operator fun plus(o: N) = N(v + o.v)
}

fun main() {
    println((N(1) + N(2) + N(3)).v)
}

Не перегружайте операторы ради изобретательности

Если именованная функция читается лучше, используйте её. Операторы предназначены для действительно числовой семантики или семантики контейнеров, а не для головоломок.

data class Log(val lines: List<String>) {
    fun append(line: String) = Log(lines + line)
}

fun main() {
    println(Log(emptyList()).append("start").lines)
}

Согласовывайте equals и hashCode

Если Вы перегружаете сравнение или проверку равенства, согласуйте equals и hashCode, чтобы не повредить коллекции.

data class Id(val v: Int)

fun main() {
    val set = hashSetOf(Id(1), Id(1))
    println(set.size)
}

Учитывайте приоритет операторов

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

data class N(val v: Int) {
    operator fun plus(o: N) = N(v + o.v)
    operator fun times(o: N) = N(v * o.v)
}

fun main() {
    println((N(2) + N(3) * N(4)).v)
}

Документируйте неожиданные операторы

Если оператор выполняет что-то неочевидное, добавьте комментарий или документацию KDoc, чтобы не вводить вызывающий код в заблуждение.

data class Range2(val start: Int, val end: Int) {
    // contains: is value inside the range?
    operator fun contains(v: Int) = v in start..end
}

fun main() {
    println(5 in Range2(1, 10))
}

Используйте contains для in

Оператор in соответствует contains. Переопределяйте его только тогда, когда принадлежность элемента множеству чётко определена для Вашего типа.

class Team(val members: List<String>) {
    operator fun contains(name: String) = name in members
}

fun main() {
    val t = Team(listOf("Ann", "Bo"))
    println("Ann" in t)
}

Если сомневаетесь, используйте функцию

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

data class Temperature(val c: Int) {
    fun warmerThan(o: Temperature) = c > o.c
}

fun main() {
    println(Temperature(30).warmerThan(Temperature(20)))
}

Быстрая проверка

Проверьте, насколько хорошо Вы поняли рекомендации по перегрузке операторов.

Итоги

Вы изучили рекомендации по перегрузке операторов:

  • Перегружайте оператор только тогда, когда его смысл очевиден и соответствует общепринятому соглашению.
  • Отдавайте предпочтение неизменяемым значениям того же типа и сохраняйте возможность объединять результаты в цепочки.
  • Разделяйте plus для значений и plusAssign для изменения.
  • Согласовывайте equals и hashCode; если именованные функции понятнее, выбирайте их.
data class V(val x: Int) {
    operator fun plus(o: V) = V(x + o.x)
}

fun main() {
    println((V(2) + V(5)).x)
}

Часто задаваемые вопросы

Урок «Лучшие практики» бесплатный?

Да — полный текст урока «Лучшие практики» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.

Чему я научусь в уроке «Лучшие практики»?

Сохраняйте интуитивность операторов Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Kotlin Academy?

Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Лучшие практики»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Kotlin Academy?

Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Функции-операторы
  2. Операторы сравнения
  3. Индексация и вызов
  4. Лучшие практики
← Назад к Kotlin Academy