Можно ли использовать немутируемый лист в Kotlin в качестве константы
Что проверяют
Знаете ли вы разницу между const val и val и понимаете ли, что List в Kotlin только для чтения, а не неизменяемый. Следом обычно спрашивают, можно ли всё-таки изменить такой список и как это влияет на Compose.
Как отвечать
Константой в смысле const val нельзя: этот модификатор разрешён только для примитивов и String, значение подставляется в код на этапе компиляции. const val TAGS = listOf("a", "b") не скомпилируется. Константой в обычном смысле можно:
- где объявлять:
valна верхнем уровне файла или вobject/companion object, имя по соглашениям Kotlin вUPPER_SNAKE_CASE; - для Java-кода:
valвcompanion objectдоступен через геттер, а@JvmFieldделает его статическим полем. Сconstи с кастомным геттером@JvmFieldне сочетается; - что даёт
listOf: интерфейсListбез методов изменения. Но на JVM за ним стоит обычная Java-коллекция: для нескольких элементов это обёртка над массивом, и приведение(list as MutableList).set(0, x)сработает.addпри этом броситUnsupportedOperationException; - где ещё дыра: если объявить
val items: List<T> = mutableList, владелец исходной ссылки продолжит менять список. И сами элементы могут быть изменяемыми, например data class сvar; - настоящая неизменяемость: библиотека
kotlinx.collections.immutableсpersistentListOf()и типамиImmutableList/PersistentList.
Для Android важен Compose. Компилятор Compose считает List нестабильным типом, потому что не может доказать неизменяемость. С режимом strong skipping, который сейчас включён по умолчанию, это менее болезненно, но ImmutableList или @Immutable на классе-обёртке делают намерение явным.
Где спотыкаются
Пишут const val для списка и удивляются ошибке компиляции. Или, наоборот, называют val константой времени компиляции, хотя вычисляется он при инициализации класса или файла.
Говорят «listOf возвращает неизменяемый список». Точнее: ссылка только для чтения, гарантий на уровне рантайма нет.
Считают, что val запрещает менять содержимое. val запрещает только переприсвоить ссылку, а val list = mutableListOf<String>() спокойно меняется через add.