Ответ
Inline-функции в Kotlin разворачиваются во время компиляции, что устраняет накладные расходы на вызов функции. Однако есть ограничения:
-
Размер кода: Каждый вызов inline-функции заменяется её телом, что увеличивает размер билда. Если функция большая или вызывается часто, это может негативно сказаться на производительности.
-
Ограничения: В inline-функциях нельзя использовать нелокальные return (кроме лямбд с
crossinline), и они не могут быть рекурсивными. -
Лямбды: Inline эффективен для функций с лямбда-параметрами, так как избегает создания анонимных классов. Но если лямбда передаётся в другую не-inline функцию, преимущество теряется.
Пример:
inline fun measureTime(block: () -> Unit) {
val start = System.currentTimeMillis()
block()
println("Time: ${System.currentTimeMillis() - start}ms")
} Ответ 18+ 🔞
Слушай, давай разберёмся с этими inline-функциями в Kotlin, а то народ часто нихуя не понимает, где их применять, а где нет. Это как с машиной — если ты будешь на каждый чих вызывать эвакуатор, то денег на бензин не останется, хотя сама идея вроде и хорошая.
Короче, суть в чём: компилятор, вместо того чтобы вызывать функцию, тупо вставляет её код прямо на место вызова. Представь, что ты вместо того чтобы крикнуть «Вася, принеси пива!», каждый раз сам встаёшь и идешь на кухню. Экономишь время на крике, но ноги болят. Это и есть инлайнинг, ёпта.
Но есть подводные камни, о которых надо помнить, а то будет вам хиросима и нигерсраки.
Во-первых, размер кода. Если функция у тебя большая, как манда с ушами, и ты её вызываешь в тысяче мест, то компилятор эту простыню текста скопипастит везде. В итоге размер твоего APK или JAR-ника раздуется, как шар перед грозой. Это называется «раздувание билда», и оно тебе нахуй не сдалось, особенно на мобилках, где каждый килобайт на счету. Поэтому инлайнить имеет смысл только небольшие функции, где выгода от избегания вызова перевешивает рост размера.
Во-вторых, ограничения. Тут как с полупидором — вроде и мужик, но не совсем. В inline-функциях нельзя делать нелокальные return из лямбд, которые туда передал, если только ты специально не пометишь параметр как crossinline. И уж точно они не могут быть рекурсивными — представь, что компилятор пытается развернуть бесконечную рекурсию. Он просто охуеет и сдаст тебе ошибку, и будет прав, пидарас шерстяной.
В-третьих, лямбды. Вот где инлайнинг реально блестит, как хуй в пальто! Обычно, когда ты передаешь лямбду в функцию, под капотом создается анонимный класс — это дополнительные расходы. А если функция inline, то лямбда тоже инлайнится, и никаких лишних объектов не создаётся. Красота! Но есть нюанс: если ты эту лямбду потом передашь куда-то ещё, в какую-то обычную (не-inline) функцию, то вся магия накрывается медным тазом. Компилятору уже не развернуть её, и он создаст тот самый объект. Так что доверия ебать ноль — всегда смотри, куда твоя лямбда идёт дальше.
Вот, смотри на пример, чтобы всё встало на свои места:
inline fun measureTime(block: () -> Unit) {
val start = System.currentTimeMillis()
block()
println("Time: ${System.currentTimeMillis() - start}ms")
}
Когда ты вызовешь measureTime { какой-то код }, компилятор не станет вызывать функцию. Он сделает вот так:
val start = System.currentTimeMillis()
какой-то код // Тело лямбды вставлено прямо сюда
println("Time: ${System.currentTimeMillis() - start}ms")
Видишь? Нет вызова measureTime, нет лишнего объекта для лямбды. Чистая магия и производительность. Но если block() внутри этой функции будет передан в какую-нибудь другую, не-inline функцию, то пиши пропало — магия исчезнет.
Короче, инструмент мощный, но как скальпель — режет хорошо, но если ты им гвозди забивать начнёшь, то сам от себя охуеешь от результата. Используй с умом, э бошка думай.