Inline-функции в Kotlin
Функции высшего порядка удобны, но у них есть цена — каждая переданная lambda в общем случае превращается в объект, который аллоцируется в куче, а её вызов идёт через виртуальный invoke(). inline убирает эту цену: компилятор копирует тело функции и её lambda-аргументы прямо в место вызова, так что объект lambda не создаётся вовсе. Это ключевая оптимизация стандартной библиотеки — forEach, let, apply все inline.
У встраивания есть неочевидное следствие, которое любят на собеседованиях. Раз тело lambda копируется в вызывающую функцию, голый return внутри такой lambda выходит из внешней функции — это non-local return. Управляют этим два модификатора: crossinline запрещает non-local return, noinline вовсе отключает встраивание параметра. Полная карта — в слоях ниже.
Карта темы
- Inline-функции — что делает
inline, зачем и почемуnoinlineисключает параметр из встраивания. - Non-local return — почему голый
returnиз встроенной lambda выходит из внешней функции и как вернуться только из lambda. - Crossinline — когда встроенную lambda нельзя пускать в другой контекст и как
crossinlineэто чинит.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
Считать inline просто подсказкой скорости | Упускаете влияние на семантику return и на reified |
| Встраивать большую функцию | Тело копируется в каждое место вызова — раздувает код |
Думать, что голый return в lambda выходит только из lambda | На деле non-local return выходит из внешней функции |
Воспринимать crossinline как безобидную оптимизацию | Это запрет non-local return — добавите зря, сломаете рабочий return |
Чинить noinline, когда нужен crossinline | noinline заодно отключает встраивание lambda |
Помечать параметр reified без inline | Не скомпилируется — reified возможен только при встраивании |
Значение для собеседований
Тему спрашивают, чтобы проверить, понимаете ли вы механику встраивания, а не только слово «быстрее». Кандидат, который объясняет «inline копирует тело в место вызова, поэтому return из lambda выходит из внешней функции, а crossinline этот выход запрещает», сразу опережает «inline — это оптимизация».
Что обычно проверяют:
- Что делает
inlineи какой ценой (размер кода против аллокации lambda). - Что такое non-local return и как вернуться только из lambda (
return@label). - Разницу
crossinlineиnoinlineи когда нужен каждый. - Связь
inlineс reified-параметрами типа.
Типичный неверный ответ: «inline кэширует результат» или «crossinline — это про производительность». На деле inline — про встраивание тела, а crossinline — про запрет non-local return, чтобы lambda можно было безопасно вызвать из другого контекста выполнения.