Ответ
Inline-функции в Kotlin стоит использовать для небольших функций, которые часто вызываются, чтобы избежать накладных расходов на вызов. Они подставляются в месте вызова, что может улучшить производительность.
Основные случаи использования:
- Функции-расширения коллекций (map, filter)
- Лямбда-параметры высокоуровневых функций
- Когда нужно избежать создания анонимного класса для лямбды
Пример:
inline fun <T> Collection<T>.filterInline(
predicate: (T) -> Boolean
): List<T> {
val result = mutableListOf<T>()
for (item in this) {
if (predicate(item)) result.add(item)
}
return result
}
Ограничения:
- Нельзя использовать для больших функций (максимум 2-3 строки)
- Нельзя использовать с reified и обычными generic-параметрами одновременно
- Нельзя вызывать из Java-кода
Ответ 18+ 🔞
Слушай, вот объясню тебе про эти inline-функции в Kotlin, чтобы ты не ломал голову, как я в своё время. Это, блядь, такая штука, которая вместо того чтобы вызываться как нормальная функция, просто вставляется прямо в код, где её используют. Представь, что ты пишешь одно и то же действие в трёх местах, а потом думаешь: "ёпта, да похуй, вынесу в функцию". А потом компилятор смотрит на твой красивый код и такой: "Э, сабака сука, зачем тебе лишний вызов?" — и просто разворачивает её обратно, как было. Хуй с горы, только без дублирования кода.
Основная фишка — производительность, особенно когда ты в лямбдах залип. Без inline каждая твоя красивая лямбда превращается в анонимный класс, а это, ядрёна вошь, лишние объекты и работа для сборщика мусора. А с inline — всё просто встаёт на место, как будто ты это вручную написал. Удивление пиздец, как это работает.
Вот тебе классика, где это реально нужно:
- Функции-расширения для коллекций. Ну, те самые
map,filter, которые ты каждый день юзаешь. Они всеinline, потому что иначе за каждую операцию над списком из трёх элементов JVM создавала бы отдельный объект — пиздопроебибна какая-то. - Когда передаёшь лямбду в функцию. Если твоя функция принимает на вход другую функцию (лямбду), и ты её помечаешь как
inline, то эта лямбда тоже "встроится" и не создаст лишний объект. Доверия ебать ноль к лишним аллокациям! - Когда хочешь избежать создания анонимного класса. Это, собственно, и есть причина всего этого цирка. Просто чтобы не засорять память ерундой.
Вот, смотри, как это выглядит в коде. Ничего сложного, обычная проверка коллекции:
inline fun <T> Collection<T>.filterInline(
predicate: (T) -> Boolean
): List<T> {
val result = mutableListOf<T>()
for (item in this) {
if (predicate(item)) result.add(item)
}
return result
}
Видишь этот inline в начале? Всё, магия началась. Когда ты вызовешь list.filterInline { it > 5 }, компилятор возьмёт тело этой функции и воткнёт его прямо в место вызова, вместо того чтобы прыгать по ссылкам. Волнение ебать, какая экономия!
Но и тут, конечно, свои подводные камни, куда ж без них. Ограничения, блядь:
- Не для монстров. Суть в том, чтобы функция была маленькой, буквально 2-3 строчки. Если ты туда целый роман впихнешь, то размер твоего скомпилированного байт-кода раздуется, как шар перед грозой. Терпения ноль ебать у того, кто будет это дебажить.
- С дженериками осторожно. Есть такая крутая фича —
reifiedtype parameters (когда ты внутриinline-функции можешь узнать реальный типT). Так вот, её нельзя просто так взять и смешать с обычными дженерик-параметрами в не-inline частях. Голову сломаешь. - Из Java — нихуя. Ну, тут всё понятно. Эта магия работает только в мире Kotlin. Если твой код дергают из Java, то
inline-функция для них будет выглядеть как самая обычная. Никакого фокуса.
Короче, юзай это дело с умом. Для мелких, часто вызываемых операций — самое то. Для всего остального — обычные функции. Главное — не пытайся быть умнее компилятора, а то будет тебе хиросима и нигерсраки в кодовой базе.