Что такое inline-функции?
inline-функции в Kotlin — это функции, при вызове которых код функции вставляется (встраивается) прямо в место вызова во время компиляции. Это отличается от обычного механизма вызова функции, где управление передаётся по ссылке.
Ключевое слово: inline
inline fun myFunction(action: () -> Unit) {
println("Before")
action()
println("After")
}
При вызове myFunction { println("Inside") } компилятор вставит весь код прямо туда, где был вызов, без создания объекта-лямбды или перехода по стеку.
📌 Зачем нужны inline-функции?
-
Устранение накладных расходов при передаче лямбд (объектов-функций).
-
Позволяют использовать return из лямбды как if/else из внешнего кода.
-
Улучшают производительность в высокочастотных функциях с лямбдами.
-
Используются в стандартной библиотеке Kotlin (let, run, apply, with, repeat и др.).
🧠 Как работает inline
До inlining:
doSomething {
println("Hello")
}
→ создаётся объект Function, передаётся внутрь doSomething, вызывается изнутри.
После inlining (на уровне байткода):
println("Before")
println("Hello")
println("After")
→ экономия на вызовах и объектах.
Пример
inline fun measure(block: () -> Unit) {
val start = System.nanoTime()
block()
val end = System.nanoTime()
println("Execution took ${end - start} ns")
}
measure {
println("Running block")
}
🔧 После компиляции будет что-то вроде:
val start = System.nanoTime()
println("Running block")
val end = System.nanoTime()
println("Execution took ${end - start} ns")
🔄 Использование return в inline-функциях
Лямбда внутри inline-функции может использовать return из внешней функции:
inline fun runIf(condition: Boolean, block: () -> Unit) {
if (condition) block()
}
fun test() {
runIf(false) {
println("Before return")
return // работает! — завершает \`test()\`, а не только лямбду
}
println("After runIf")
}
⚠️ Когда не стоит делать inline
-
Для крупных функций: вставка кода может сильно раздуть байткод.
-
Если лямбда не используется — inlining бесполезен.
-
В inline-функции не должно быть рекурсии (компилятор не позволит).
🔐 noinline и crossinline
noinline
По умолчанию все лямбды инлайнится. Если вы хотите передать одну из них дальше (например, в другую функцию), используйте noinline:
inline fun doTwice(block1: () -> Unit, noinline block2: () -> Unit) {
block1()
block2()
}
→ block1 будет встроен, а block2 — нет.
crossinline
Нельзя использовать return внутри inline-лямбды, если она передаётся в другой контекст (например, в Thread, Runnable, coroutine). Тогда — crossinline:
inline fun launch(block: () -> Unit) {
val r = Runnable {
// block() // ошибка: \`return\` нельзя использовать
// решение:
block()
}
Thread(r).start()
}
→ crossinline запрещает non-local return внутри такой лямбды.
Применение в Android и Kotlin DSL
-
inline активно используется в DSL (build.gradle.kts, Anko, Jetpack Compose).
-
Используется для оптимизации кода с лямбдами.
-
В Jetpack Compose почти все модификаторы — inline.
Итого
Особенность | Описание |
---|---|
inline | Встраивает тело функции в место вызова |
--- | --- |
Зачем? | Уменьшить накладные расходы от лямбд, ускорить выполнение |
--- | --- |
noinline | Отключает inlining для отдельных параметров |
--- | --- |
crossinline | Запрещает return из лямбды, если она передаётся в другой контекст |
--- | --- |
Когда полезен | Часто вызываемые функции с лямбдами, DSL, Compose, корутины |
--- | --- |
Когда вреден | В больших функциях, при нарушении читаемости, увеличении размера байткода |
--- | --- |
inline — один из мощных инструментов Kotlin, который позволяет писать выразительный и эффективный код без жертв в производительности.