Извлечение через !
Коробку с подарком можно открыть аккуратно, а можно разорвать упаковку не глядя. Если подарок внутри, он сразу у вас в руках. Если коробка пуста, вас ждёт неприятный сюрприз.
В Swift так поступает ! после опционала. Компилятор требует извлечь значение, и ! — самый короткий способ это сделать:
let typed = "42"
let number = Int(typed)!
print(number + 1) // 43Давайте разберём программу по строкам:
Int(typed)даёт опционалInt?, в котором лежит42.!открывает коробку без проверки, иnumberполучает обычное число42типаInt.number + 1складывается без ошибки, и программа печатает43.
Это не тот !, что меняет true на false: логическое НЕ пишут перед значением (!isVip), а извлечение — после опционала (Int(typed)!).
Извлечение через ! называют принудительным извлечением: коробку открывают, не проверяя, есть ли в ней что-нибудь. А если в тексте не число?
let broken = Int("4x2")! // ✗
print(broken + 1)Fatal error: Unexpectedly found nil while unwrapping an Optional valueКомпилятор эту программу пропустил: он не проверяет, что даст Int(…). Это выяснится только при запуске. Во время работы Int("4x2") дал nil, ! открыл пустую коробку и программа аварийно завершилась на этой строке. print уже не выполнился.
Как читать сообщение
Сообщение состоит из двух частей:
Fatal error— аварийное завершение: программа остановилась и дальше не работает;Unexpectedly found nil while unwrapping an Optional value— «при извлечении опционала неожиданно нашёлсяnil».
В терминале перед сообщением стоят имя файла и номер строки. Ниже может появиться длинный отчёт об аварии со словами Illegal instruction, но причину называет именно строка Fatal error. Xcode в таком случае останавливается на самой строке с ! и показывает то же сообщение рядом с ней.
Это не ошибка компиляции, а ошибка во время работы. Программа собралась, запустилась и остановилась только тогда, когда дошла до ! с пустой коробкой.
Здесь картинка с коробкой неточна. В жизни разорванная пустая коробка только огорчает, а праздник продолжается. В Swift ! на пустом опционале останавливает всю программу.
Когда ! допустим
Значение точно есть
! пишут, только когда nil невозможен по смыслу программы, а его появление означало бы ошибку в самом коде. Например, текст записан прямо в программе и вы видите, что в нём число: Int("100")! всегда даёт 100. Если такой nil всё же появится, программе лучше сразу остановиться, чем работать дальше с неверными данными.
Данные снаружи
Текст от пользователя, из файла или из сети может оказаться каким угодно. Для таких данных ! не подходит: открывайте их опционалы через if let, guard let или ??. Тогда пустая коробка уведёт программу в отдельную ветку или заменится значением по умолчанию, а не остановит работу.
Этот вопрос часто задают на собеседовании: «Почему ! опасен и когда его можно писать?» Ответ состоит из двух частей:
!наnilаварийно завершает программу во время работы, и компилятор этого не ловит;!уместен, только когдаnilпо смыслу невозможен, а в остальных случаях значение извлекают безопасно.
Частая ошибка
От ! ждали нуля вместо пустоты:
let stock: Int? = nil
print(stock! + 5) // ✗Ожидали 5, будто ! превращает nil в 0. Но ! не придумывает значение: программа аварийно завершится с тем же Fatal error. Если вместо nil нужен ноль, так и напишите: (stock ?? 0) + 5 даёт 5.
Главное
!извлекает значение из опционала без проверки:Int("42")!даёт42типаInt.!наnilаварийно завершает программу с сообщениемFatal error: Unexpectedly found nil while unwrapping an Optional value.- Компилятор не ловит такую ошибку: она случается во время работы, на строке с
!. !пишут, только когдаnilпо смыслу невозможен, а данные снаружи открывают черезif let,guard letили??.