Какие типы данных может принимать константа в Kotlin и есть ли ограничения
Что проверяют
Отличаете ли вы const val от просто val и понимаете ли, что происходит с константой при компиляции. Следом спрашивают, почему const val нельзя объявить в обычном классе и зачем константы нужны в аннотациях.
Как отвечать
const val принимает только примитивные типы (Int, Long, Short, Byte, Double, Float, Char, Boolean) и String. Nullable-типы, коллекции, enum и объекты запрещены.
Ограничения по месту и значению:
- где объявлять: на верхнем уровне файла, в
objectили вcompanion object. В теле обычного класса и внутри функции нельзя; - чем инициализировать: выражением, которое компилятор вычисляет сам: литерал, арифметика, строковый шаблон из других констант (
"$BASE_URL/api"). Вызов функции, даже чистой, не подходит; - никаких геттеров: собственный
get()запрещён.
Компилятор подставляет значение прямо в места использования. Поэтому константы годятся для аргументов аннотаций (@Entity(tableName = TABLE) и @Query в Room), а в Java константа из companion object видна как public static final поле без @JvmField.
Для всего остального есть val. Это переменная только для чтения, а не константа: тип любой, значение вычисляется при инициализации. val можно объявить с кастомным геттером, который каждый раз возвращает новое значение, а val users = mutableListOf<User>() запрещает только переприсваивание, сам список меняется свободно.
Где спотыкаются
Называют val items = listOf(...) неизменяемой константой. List в Kotlin это интерфейс только для чтения: методов изменения у него нет, но никто не гарантирует, что список не поменяют через другую ссылку. Настоящую неизменяемость дают kotlinx.collections.immutable.
Забывают про инлайнинг. Библиотека поменяла const val, а модуль, который её не пересобрал, продолжает использовать старое значение.
Пишут const val в обычном классе, ожидая аналог static. Нужен companion object или верхний уровень файла.