Когда что использовать
Компромиссы
«Когда что использовать» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.
Два инструмента — разные задачи
Инфиксные функции предназначены для читаемости, а функции с модификатором tailrec — для безопасной и эффективной рекурсии. Они решают разные задачи.
infix fun Int.add(o: Int) = this + o
tailrec fun sum(n: Int, acc: Int = 0): Int =
if (n == 0) acc else sum(n - 1, acc + n)
fun main() {
println(2 add 3)
println(sum(10))
}Выбирайте инфиксные функции для выразительных API
Выбирайте инфиксную запись, когда вызов становится понятнее без точек и скобок, особенно в DSL и при создании пар.
fun main() {
val pair = "id" to 100
println(pair)
}Выбирайте tailrec для глубокой рекурсии
Используйте tailrec, когда рекурсивный алгоритм может быть достаточно глубоким, чтобы вызвать переполнение стека.
tailrec fun count(n: Int, acc: Int = 0): Int =
if (n == 0) acc else count(n - 1, acc + 1)
fun main() {
println(count(50000))
}Компромиссы инфиксной записи
Инфиксная запись убирает знаки пунктуации, что может затруднить понимание для незнакомых читателей и усложнить работу с приоритетом операций. Используйте её только тогда, когда она явно помогает.
infix fun Int.scaledBy(f: Int) = this * f
fun main() {
println(5 scaledBy 3)
}Компромиссы tailrec
Для превращения кода в хвостовую рекурсию часто требуется Accumulator, из-за чего код может казаться менее прямолинейным, чем обычный цикл. Сопоставляйте выразительность с простотой.
tailrec fun product(n: Int, acc: Long = 1): Long =
if (n <= 1) acc else product(n - 1, acc * n)
fun main() {
println(product(6))
}Когда цикл проще
Если обычный цикл for или while понятнее хвостовой рекурсии, выбирайте цикл. Рекурсия — это инструмент, а не обязательное требование.
fun sumLoop(n: Int): Int {
var total = 0
for (i in 1..n) total += i
return total
}
fun main() {
println(sumLoop(10))
}Когда именованный вызов понятнее
Если имя инфиксной функции явно не обозначает бинарное отношение, обычный вызов метода лучше передаёт намерение.
data class Temp(val c: Int) {
fun isWarmerThan(o: Temp) = c > o.c
}
fun main() {
println(Temp(30).isWarmerThan(Temp(20)))
}Сочетание обоих подходов
Эти две возможности независимы: одна программа может использовать инфиксную запись для читаемых вызовов, а tailrec — для безопасной рекурсии.
infix fun Int.upto(n: Int) = (this..n).toList()
tailrec fun last(list: List<Int>): Int =
if (list.size == 1) list[0] else last(list.drop(1))
fun main() {
println(last(1 upto 5))
}Проверка читаемости
Спросите себя: делает ли инфиксная запись вызов понятнее новичку? Предотвращает ли tailrec реальный риск переполнения стека? Если нет, отдайте предпочтение обычным функциям и циклам.
fun main() {
val r = (1..5).sum()
println(r)
}Примечание о производительности
tailrec обеспечивает производительность, сопоставимую с циклом, при постоянном объёме стека. Инфиксная запись не требует дополнительных затрат во время выполнения и является исключительно синтаксической возможностью.
tailrec fun pow(base: Int, exp: Int, acc: Long = 1): Long =
if (exp == 0) acc else pow(base, exp - 1, acc * base)
fun main() {
println(pow(2, 10))
}Краткое руководство по выбору
Инфиксная запись: выразительные двоичные вызовы с одним аргументом. Tailrec: рекурсия, которая должна безопасно обрабатывать большие объёмы данных. Ни один из вариантов не является выбором по умолчанию — оба требуют осознанного решения.
infix fun String.joinWith(o: String) = "$this-$o"
fun main() {
println("a" joinWith "b")
}Быстрая проверка
Проверьте, насколько хорошо Вы поняли, когда использовать каждую возможность.
Итоги
Вы узнали, когда использовать каждую возможность:
- Используйте
infixдля выразительных и читаемых двоичных вызовов и DSL. - Используйте
tailrecдля рекурсии, которая должна масштабироваться без переполнения стека. - Отдавайте предпочтение обычным циклам или именованным функциям, если они понятнее.
- Эти две возможности независимы и могут сочетаться.
infix fun Int.by(o: Int) = this * o
tailrec fun dec(n: Int): Int = if (n == 0) 0 else dec(n - 1)
fun main() {
println(3 by 4)
println(dec(1000))
}Изучай Kotlin с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 51
- Уроки
- 203
Часто задаваемые вопросы
Урок «Когда что использовать» бесплатный?
Да — полный текст урока «Когда что использовать» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 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 — локальная установка не требуется.
Все уроки этого курса
- Инфиксные функции
- Создание API в стиле DSL
- Функции tailrec
- Когда что использовать