Инлайн-классы в Kotlin 1.3

kotlin

Zero-cost* abstractions in Kotlin — статья с подробным объяснением новой экспериментальной языковой конструкции Kotlin под названием inline-классы.

Одна из ключевых особенностей языка Kotlin — null safety, которая гарантирует, что программист не сможет по ошибке вызвать методы объекта, имеющего значение null, или передать этот объект в качестве аргумента другим методам. Null safety существенно повышает надежность кода, но не защищает от других ошибок программиста.

Допустим, у тебя есть база котов и собак, которых ты идентифицируешь по ID. Также у тебя есть метод getDogById(dogId: Long), который возвращает информацию о собаке с конкретным ID. Очевидно, что, если в качестве ID собаки ты передашь методу ID кошки, это будет ошибкой, которая приведет к неопределенному результату. Но ни среда разработки, ни компилятор не скажут тебе о ней.

РЕКОМЕНДУЕМ:
Хорошие и плохие приемы программирования на Kotlin

Еще во времена Java программисты придумали метод обойти эту проблему с помощью так называемых классов-оберток. Ты просто создаешь класс DogId с единственным полем (ID собаки) и используешь его везде, где раньше использовал тип Long в качестве ID. Все остальное компилятор и среда разработки сделают за тебя: они просто не позволят передать DogId в качестве аргумента функции, которая ожидает CatId, — это ошибка.

Но есть в классах-врапперах одна проблема. Создание объектов не самая дешевая операция. Если ты будешь плодить их на каждый чих, то вскоре заметишь возросшее потребление оперативной памяти и процессорных ресурсов.

И здесь на сцену выходят инлайн-классы. По своей сути инлайн-класс — это класс-враппер с одним параметром, который при компиляции разворачивается в этот параметр, чтобы избежать накладных расходов. Например:

Данный код написан с использованием враппера, чтобы избежать описанной выше ошибки. Однако при компиляции объект DogId будет заменен Long, так что никаких дополнительных накладных расходов не потребуется.

Компилятор накладывает следующие ограничения на инлайн-классы:

  • не больше одного параметра;
  • никаких теневых полей;
  • никаких блоков инициализации;
  • никакого наследования.

Однако инлайн-классы могут:

  • реализовать интерфейс;
  • иметь свойства и функции.

Также стоит иметь в виду, что инлайн-классы не всегда будут развернуты в свой параметр. Главное правило здесь: объект инлайн-класса не будет развернут, если используется в качестве аргумента функции, ожидающей другой тип.

Например, функции для работы с коллекциями ( listOf(), setOf() и им подобные) обычно принимают на вход параметр типа Object или Any, так что переданный им объект инлайн-класса развернут не будет. Функция equals() также принимает в качестве аргумента тип Any, поэтому следующие два примера работают одинаково, но второй приведет к дополнительным накладным расходам:

Объект не будет развернут и если объект инлайн-класса передать функции, аргумент которой имеет nullable-тип:

Интересно также, что компилятор поддерживает переопределение функций, принимающих объект инлайн-класса и его необернутый аналог. То есть следующий код будет успешно скомпилирован:

РЕКОМЕНДУЕМ:
Полезные советы разработчику на языке Kotlin

Ну и последнее, что стоит иметь в виду: инлайн-классы — это экспериментальная возможность, которая может измениться со временем или будет удалена.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий