Inline функции

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

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

Ключевое слово inline должно быть указано перед объявлением функции. Кроме того, внутри тела inline-функции можно использовать другие ключевые слова, такие как noinline для предотвращения инлайнинга для определенных лямбда-выражений или функций высшего порядка.

Noinline

Ключевое слово noinline используется в Kotlin в контексте inline-функций и лямбда-выражений, чтобы указать, что некоторые из аргументов функции или лямбда-выражения не должны быть встроены в вызывающий код, даже если функция сама является inline.

Когда вы помечаете параметры функции noinline, это означает, что компилятор не будет инлайнить (встраивать) лямбда-выражения, переданные в качестве таких аргументов, в вызывающий код. Вместо этого они будут создавать объекты, как если бы функция не была объявлена inline.

inline fun executeWithLogging(logMessage: () -> Unit, 
							  noinline action: () -> Unit) {
    println("Executing log message")
    logMessage()
    println("Executing action")
    action()
}

fun main() {
    val message = { println("This is a log message") }
    val action = { println("This is an action") }
    executeWithLogging(message, action)
}

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

Вот когда не следует использовать noinline:

  1. Когда все лямбда-выражения, переданные в качестве аргументов функции, могут быть инлайнены без проблем.
  2. Когда вы хотите оптимизировать производительность за счет инлайнинга всех лямбда-выражений.
  3. Когда функция вызывается в контексте, где невозможно или нежелательно создание объектов для лямбда-выражений.

crossinline

crossinline нужен, чтобы предотвратить ситуацию, когда внутри лямбды вы пытаетесь выйти из внешней функции с помощью return. Это важно, если лямбда передаётся в другой код, где такой выход был бы некорректен, например, в функцию, которая выполняется в другом месте или позже. По сути, crossinline говорит: "В этой лямбде нельзя использовать return, который выйдет за её пределы."

fun doSomething(action: () -> Unit) {
    println("Before action")
    action()
    println("After action")
}

inline fun executeCrossinline(crossinline action: () -> Unit) {
    doSomething {
        // Здесь нельзя использовать return для выхода из executeCrossinline,
        // потому что action помечен как crossinline.
        action()
    }
}

fun main() {
    executeCrossinline {
        println("Inside action")
        // return // Это вызовет ошибку компиляции
    }
}
  1. В функции executeCrossinline параметр action помечен как crossinline.
  2. Когда мы передаём action в функцию doSomething, мы не можем использовать return внутри этой лямбды для выхода из executeCrossinline. Это запрещено, потому что crossinline гарантирует, что неконечные возвраты невозможны.
  3. Если бы вы попытались использовать return внутри лямбды, это вызвало бы ошибку компиляции.

Таким образом, crossinline защищает код от некорректных возвратов, которые могут нарушить выполнение программы.