Предскажите результат и объясните, как is учитывает Optional в этом коде: пример с кодом

Предскажите результат и объясните, как is учитывает Optional в этом коде:

let value: Int? = 42

print(value is Int)
print(value is Int?)
Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Код напечатает:

true true

Проверка value is Int успешно извлекает непустое значение из Optional, а value is Int? проверяет совместимость с самим типом Optional. Статический тип выражения остаётся Int?; оператор is выполняет проверку совместимости типов во время выполнения.

Исторический контекст

Optional появился как типобезопасный способ представить отсутствие значения без неявного null и связанных с ним аварийных ошибок. Поэтому значение Int? хранит либо Int, либо nil, а компилятор заставляет явно учитывать возможность отсутствия значения.

При этом Swift поддерживает работу с динамическими типами через Any, is, as? и pattern matching. Эти механизмы должны корректно обрабатывать не только сами значения, но и их Optional-обёртки.

Постановка проблемы

Статический тип valueInt?, поэтому легко ошибочно предположить, что проверка value is Int обязана вернуть false. На практике оператор проверяет не простое совпадение написанных в коде типов, а возможность привести фактическое значение к целевому типу.

Неверное понимание этого поведения приводит к путанице между статическим типом выражения, фактическим наличием значения и результатом динамического приведения. Особенно опасно считать, что успешная проверка is уже даёт доступ к значению как к не-Optional.

Подробное решение

В value находится Optional.some(42). При проверке value is Int Swift видит непустой Optional и проверяет его содержимое: 42 совместимо с Int, поэтому результат — true.

Проверка value is Int? также возвращает true, поскольку исходное значение уже имеет тип Int?. Для непустого Optional обе проверки успешны, но они проверяют разные целевые типы: содержимое и обёртку соответственно.

Оператор is ничего не извлекает в переменную и не изменяет тип value. Он возвращает только Bool. Для безопасного использования содержимого требуется отдельное извлечение:

let value: Int? = 42 if let number = value, number is Int { print(number + 1) }

Здесь if let делает number типом Int, а is Int уже избыточен: после успешного извлечения статический тип number и так равен Int. Поэтому в обычном коде для Optional следует применять optional binding, а не использовать is как замену извлечению.

Для nil результат проверки содержимого был бы иным: nil is Int возвращает false, потому что извлечь значение типа Int невозможно. Проверка совместимости с Optional может быть успешной, поскольку само значение имеет Optional-тип, но конкретное поведение следует рассматривать с учётом целевого уровня обёртки.

Ситуация из практики

Представим обработчик данных из внешнего источника, где значение имеет тип Any и может быть числом или отсутствовать. Вариант с проверкой is позволяет узнать, совместимо ли значение с типом, но не даёт самого числа:

let raw: Any = Optional<Int>.some(42) if raw is Int { print("число найдено") }

Проблема такого решения — неочевидная работа с Optional-слоем и отсутствие извлечённого значения. Принудительное приведение через as! Int короче, но при неожиданном типе завершит приложение аварийно.

Условительное приведение as? Int безопаснее, однако его результат снова будет Optional и потребует обработки nil. Для внешних данных предпочтителен вариант с условительным приведением и явной веткой ошибки: он не скрывает отсутствие значения и не приводит к аварийному завершению.

Что кандидаты часто упускают

  1. Вопрос: Превращает ли успешная проверка value is Int переменную value из Int? в Int?

    Ответ: Нет. is возвращает только Bool и не меняет статический тип выражения. Чтобы получить Int, нужен if let, guard let или другой способ извлечения Optional.

  2. Вопрос: Почему для let value: Int? = nil проверка value is Int не может быть успешной?

    Ответ: У Optional нет содержащего значения, которое можно было бы проверить или привести к Int. Поэтому проверка содержимого завершается false. Сам факт наличия типа Int? не означает наличие объекта типа Int внутри него.

  3. Вопрос: Чем is Int отличается от as? Int для Optional-значения?

    Ответ: is Int возвращает только признак совместимости типов — Bool. as? Int выполняет условительное приведение и возвращает извлечённое значение типа Int?: при успехе — число, при неуспехе — nil. Поэтому as? применяют, когда после проверки нужно использовать результат, а is — когда достаточно самого факта совместимости.