← Назад к вопросам

Для чего нужен noinline?

2.0 Middle🔥 21 комментариев
#Kotlin основы#Производительность и оптимизация

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Назначение noinline в Kotlin

noinline — это модификатор для параметров функций высшего порядка, который ЗАПРЕЩАЕТ компилятору Kotlin встраивать (inline) лямбду в код вызывающей функции.

Что такое inline?

По умолчанию функции с параметром-лямбдой пишутся с inline для оптимизации:

// По умолчанию: лямбда встраивается в код вызывающей функции
inline fun forEach(action: (Int) -> Unit) {
    for (i in 1..3) {
        action(i)
    }
}

// Использование
forEach { i -> println(i) }

// После inlining (то, что делает компилятор):
for (i in 1..3) {
    println(i)
}

Что делает noinline?

noinline отменяет встраивание для конкретного параметра:

inline fun myFunction(
    inlineParam: (Int) -> Unit,      // Будет встроена
    noinline noInlineParam: (Int) -> Unit  // НЕ будет встроена
) {
    inlineParam(1)    // Встраивается (нет вызова функции)
    noInlineParam(2)  // Обычный вызов функции
}

Зачем нужен noinline?

1. Сохранение лямбды в переменную

Без noinline компилятор не позволит сохранить лямбду, потому что она встраивается:

// ❌ Ошибка (inline не может быть сохранена)
inline fun saveCallback(callback: (Int) -> Unit) {
    val stored = callback // IllegalStateException!
}

// ✅ Правильно с noinline
inline fun saveCallback(noinline callback: (Int) -> Unit) {
    val stored = callback // OK
    stored.invoke(42)
}

2. Передача лямбды дальше (как параметр)

// ❌ Inline нельзя передавать
inline fun processAndPass(action: (Int) -> Unit) {
    processInThread(action) // Ошибка!
}

// ✅ С noinline работает
inline fun processAndPass(noinline action: (Int) -> Unit) {
    processInThread(action) // OK
}

fun processInThread(action: (Int) -> Unit) {
    Thread { action(42) }.start()
}

3. Сохранение в коллекции

// ❌ Inline нельзя в список
inline fun registerHandlers(handler: (String) -> Unit) {
    val list = mutableListOf<(String) -> Unit>()
    list.add(handler) // Ошибка!
}

// ✅ С noinline работает
inline fun registerHandlers(noinline handler: (String) -> Unit) {
    val list = mutableListOf<(String) -> Unit>()
    list.add(handler) // OK
}

Производительность: inline vs noinline

Параметрinlinenoinline
Размер кодаУвеличиваетсяНормальный
СкоростьБыстрееМедленнее (вызов функции)
Возможность сохранить❌ Нет✅ Да
Когда использоватьЧасто вызываемыеРедко вызываемые

Практический пример

class EventBus {
    private val listeners = mutableListOf<(Event) -> Unit>()
    
    // ✅ Правильно: используем noinline для сохранения
    fun subscribe(noinline listener: (Event) -> Unit) {
        listeners.add(listener)
    }
    
    // ❌ Неправильно: inline не сможет сохраниться
    // fun subscribe(listener: (Event) -> Unit) { ... }
    
    fun emit(event: Event) {
        // ✅ Здесь можно использовать inline
        listeners.forEach { listener -> listener(event) }
    }
}

class MyActivity {
    fun onCreate() {
        val bus = EventBus()
        
        // Лямбда сохраняется, поэтому нужен noinline
        bus.subscribe { event ->
            println("Получено: $event")
        }
    }
}

Ещё примеры использования

Функция со смешанными параметрами:

inline fun retryOnFailure(
    times: Int,
    block: (Int) -> Unit,           // inline (встроится)
    noinline onError: (Exception) -> Unit  // noinline (передаётся дальше)
) {
    repeat(times) { attempt ->
        try {
            block(attempt) // Встраивается, быстро
        } catch (e: Exception) {
            onError(e) // Обычный вызов
        }
    }
}

crossinline для вложенных корутин:

inline fun runAsync(
    crossinline block: suspend () -> Unit
) {
    GlobalScope.launch {
        block() // Используется в suspend функции
    }
}

Итог

noinline нужен когда:

  • Нужно сохранить лямбду в переменную
  • Передать лямбду в другую функцию
  • Сохранить лямбду в коллекции
  • Лямбда используется в контексте, где inline невозможен

Без noinline:

  • Компилятор встраивает лямбду для оптимизации
  • Код работает быстрее, но зато увеличивается размер
  • Лямбду нельзя сохранить
Для чего нужен noinline? | PrepBro