Для чего нужно ключевое слово crossinline в inline функции

Ответ

crossinline используется в inline функциях для запрета нелокального возврата (return) из лямбды, переданной в такую функцию.

Проблема:
В обычной inline функции return внутри лямбды завершает внешнюю функцию, что может быть неожиданно:

inline fun runInline(block: () -> Unit) {
    block()
}

fun main() {
    runInline { 
        println("Before return")
        return // Неожиданно завершает main()
    }
    println("This won't execute")
}

Решение:
Добавляем crossinline, чтобы запретить return:

inline fun runCrossInline(crossinline block: () -> Unit) {
    block()
}

fun main() {
    runCrossInline { 
        println("Before return")
        // return // Ошибка компиляции: Can't return here
    }
    println("This will execute")
}

Где используется:
Чаще всего в асинхронных вызовах (например, view.post { ... }), где нелокальный return нарушил бы логику.

Ответ 18+ 🔞

А, ну это про crossinline! Слушай, тут история простая, но если не вникнуть — можно ебушки-воробушки получить.

Вот смотри: есть у нас inline функции. Они, блядь, хорошие — производительность улучшают, потому что код вставляется прямо на место вызова, а не вызывается как отдельная функция. Но есть у них одна хитрая жопа: если ты в лямбде внутри такой функции напишешь return, то он выйдет не только из лямбды, а из всей внешней функции, которая эту inline-функцию вызвала. Представляешь?

inline fun runInline(block: () -> Unit) {
    block()
}

fun main() {
    runInline { 
        println("Перед возвратом")
        return // Ёпта! Этот return завершит всю функцию main()!
    }
    println("А эта строка уже не выполнится") // Сюда мы никогда не попадём
}

Вот это пиздец, да? Ты думаешь, что возвращаешься из лямбды, а на самом деле — бац, и вся твоя программа накрылась медным тазом. Удивление пиздец, когда такое впервые встречаешь.

И вот тут на сцену выходит наш спаситель — crossinline. Это модификатор, который ты вешаешь на параметр-лямбду. Он говорит компилятору: "Чувак, эту лямбду всё равно inline'ь, но запрети в ней нелокальные returnы! Пусть возвращается только внутри себя, как нормальная лямбда".

inline fun runCrossInline(crossinline block: () -> Unit) {
    block()
}

fun main() {
    runCrossInline { 
        println("Перед возвратом")
        // return // Ошибка компиляции! Нельзя тут! Can't return here
        // Можно только return@runCrossInline — локальный возврат к метке
    }
    println("А эта строка благополучно выполнится") // Всё работает!
}

Где это, блядь, нужно? Да везде, где лямбда выполняется не прямо сейчас, а потом. Например, ты передаёшь её в какой-нибудь асинхронный вызов типа view.post { ... }. Представь: функция post отработала и завершилась, а твоя лямбда выполнится только через 16 миллисекунд, когда придёт следующий кадр отрисовки. Какой нахуй return из внешней функции может быть в этом случае? Внешняя функция уже давно завершилась! Это же бред, ёперный театр. Вот crossinline и спасает от таких граблей.

Короче, запомни: хочешь запретить return, который выпрыгивает из лямбды наружу — добавляй crossinline. Всё просто, как три копейки.