ПрограммированиеBackend разработчик

Что такое smart casting в Kotlin? Как он работает с условиями, when-выражением, nullable-типами, кастомными геттерами и свойствами? Приведите примеры и подводные камни.

Проходите собеседования с ИИ помощником Hintsage

Ответ.

Smart casting — это механизм, при котором компилятор Kotlin автоматически "понижает" тип после проверки на определённый тип или null. Это позволяет использовать свойства и методы того типа, в который произведён каст, без явного преобразования.

Пример:

fun demo(x: Any) { if (x is String) { println(x.length) // x автоматически приведён к String } }

Работает с:

  • is / !is операторами (например, в if или when)
  • Nullable-переменными (if (x != null))
  • when-выражениями

Не работает:

  • Когда свойство имеет кастомный геттер (компилятор теряет уверенность, что значение не изменилось между проверкой и использованием)
  • Для open/var свойств класса

Пример с nullable:

val str: String? = getString() if (str != null) println(str.length) // smart cast

Когда не работает:

val something: Any get() = fetch() if (something is String) { println(something.length) // Error: smart cast невозможен }

Вопрос с подвохом.

Можно ли рассчитывать на smart cast для open или var свойств класса внутри методов?

Нет! Smart cast работает только с локальными переменными и val-свойствами в final-классах. Для открытых (open) или var-свойств, компилятор не уверен, может ли значение измениться другими потоками или потомками. Для них требуется ручной cast или локальная переменная.

open class Base { open var maybeString: Any? = "abc" fun check() { if (maybeString is String) { // println(maybeString.length) // Error: Smart cast невозможен val asString = maybeString as String println(asString.length) // Явный cast } } }

Примеры реальных ошибок из-за незнания тонкостей темы.


История

В одном проекте для логики экранов использовали open var свойства model данных. Программист полагался на smart-cast после проверки if (model is SomeType), однако при компиляции пришлось все вручную приводить типы, что ухудшило читаемость и добавило код дублирования из-за незнания ограничения smart cast на var/open.


История

При получении данных через геттер (например, через делегат или валидацию), smart cast для значения не сработал. Разработчик не понял причин и несколько часов тратил на отладку, пока не выяснил, что компилятор не применяет smart cast к таким геттерам, т.к. они могут возвращать разное значение между вызовами.


История

В проекте при обработке nullable-значений через if (obj != null) smart cast работал внутри ветки, а при распараллеливании кода появлялись NullPointerException из-за обращений вне области гарантии. Это показало недостаточное понимание локального действия smart cast и особенностей многопоточных сценариев работы с nullable-переменными.