Как работает safe cast (as?)?

Safe cast в Kotlin — это безопасная операция приведения типа с использованием оператора as?. Она позволяет попытаться привести объект к определённому типу и не выбрасывает исключение, если приведение невозможно. Вместо этого возвращается null.

Общий синтаксис

val obj: Any = "Hello"
val str: String? = obj as? String

Если obj действительно является String, то str получит это значение. Если нет — str будет null.

Отличие от обычного as

Обычное приведение as:

val number: Any = 123
val text = number as String // выбросит ClassCastException

В этом случае программа упадёт с ошибкой:

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

С использованием safe cast:

val number: Any = 123
val text = number as? String // text = null

Здесь всё безопасно — если тип не совпадает, переменная получит null, а не выбросится исключение.

Где применяется

  1. **Проверка и обработка разных типов во время выполнения:
    **
fun handleInput(input: Any) {
val str = input as? String
if (str != null) {
println("Это строка длиной ${str.length}")
} else {
println("Это не строка")
}
}
  1. **Работа с дженериками и динамическими типами:
    **
fun parseJson(value: Any): Map<String, Any>? {
return value as? Map<String, Any>
}
  1. **Использование в when:
    **
fun process(value: Any) {
when (val result = value as? String) {
null -> println("Не строка")
else -> println("Строка длиной ${result.length}")
}
}

Комбинация с let и ?.

val value: Any = 42
(value as? String)?.let {
println("Это строка: $it")
}

Если value не строка, блок let не выполнится.

Вложенные касты

Safe cast можно применять к вложенным структурам:

val list: Any = listOf(1, 2, 3)
val intList = list as? List<Int> // сработает
val strList = list as? List<String> // null

Однако нужно помнить, что as? List<String> — это unchecked cast, и Kotlin не сможет гарантировать тип элементов. Приведение пройдёт, даже если тип не тот, так как проверяется только контейнер (List), а не содержимое (String).

Когда не использовать

Safe cast стоит применять только в ситуациях, где null — это допустимое поведение, и вы готовы корректно обработать его. В противном случае это может скрыть ошибки, особенно если null затем используется без проверки.

Пример из реального кода

fun logIfString(value: Any) {
(value as? String)?.let {
println("Логируем строку: $it")
}
}

Если value — строка, она будет залогирована. Если нет — ничего не произойдёт.

Safe cast — удобный и безопасный инструмент в Kotlin для случаев, когда тип объекта может быть неизвестен, и мы хотим избежать аварийного завершения программы при приведении типов.