Перейти к содержимому
Теория · Опционалы · урок 7 из 8

Извлечение через !

Коробку с подарком можно открыть аккуратно, а можно разорвать упаковку не глядя. Если подарок внутри, он сразу у вас в руках. Если коробка пуста, вас ждёт неприятный сюрприз.

В Swift так поступает ! после опционала. Компилятор требует извлечь значение, и ! — самый короткий способ это сделать:

SWIFT
let typed = "42"
let number = Int(typed)!
print(number + 1) // 43

Давайте разберём программу по строкам:

  1. Int(typed) даёт опционал Int?, в котором лежит 42.
  2. ! открывает коробку без проверки, и number получает обычное число 42 типа Int.
  3. number + 1 складывается без ошибки, и программа печатает 43.

Это не тот !, что меняет true на false: логическое НЕ пишут перед значением (!isVip), а извлечение — после опционала (Int(typed)!).

Извлечение через ! называют принудительным извлечением: коробку открывают, не проверяя, есть ли в ней что-нибудь. А если в тексте не число?

SWIFT
let broken = Int("4x2")! // ✗
print(broken + 1)
TEXT
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 по смыслу невозможен, а в остальных случаях значение извлекают безопасно.

Частая ошибка

От ! ждали нуля вместо пустоты:

SWIFT
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 или ??.