Исключение, которое не распространяется

Я столкнулся с этим глупым поведением в swift, где принудительное разворачивание необязательно не распространяется.

Из документации:

Попытка использовать! для доступа к несуществующему необязательному значению запускается ошибка времени выполнения. Всегда проверяйте, чтобы опциональное значение содержало ненулевое значение перед использованием! чтобы развернуть ее значение.

Воспроизведение:

func foo(bar:String?) throws{
    print(bar!);
}

и

try foo(nil);

Это не кажется логичным или последовательным для меня, и я не могу найти документацию по этому вопросу.

Это по дизайну?

Ответы

Ответ 1

Из documentation:

Обработка ошибок

Обработка ошибок - это процесс реагирования и восстановления ошибки в вашей программе. Swift предоставляет первоклассную поддержку для метания, ловушки, размножения и манипулирования восстанавливаемыми ошибок во время выполнения.

...

Ошибки представления и метания

В Swift ошибки представлены значениями типов, которые соответствуют протокол ErrorType. Этот пустой протокол указывает, что тип может для обработки ошибок.

(Примечание: ErrorType было переименовано в Error в Swift 3)

Итак, при try/catch вы обрабатываете ошибки Swift (значения типов, соответствующие протоколу ErrorType), которые throw n. Это полностью не связано с ошибками времени выполнения и исключениями времени выполнения (а также не связан с NSException из библиотеки Foundation).

Обратите внимание, что в документации Swift по обработке ошибок даже не используется слово "исключение", за единственным исключением (!) в (выделение мое) в:

Примечание

Обработка ошибок в Swift напоминает обработку исключений в других языков, с использованием ключевых слов try, catch и throw. В отличие от обработка исключений на многих языках, включая Objective-C -error обработка в Swift не предполагает разворачивания стека вызовов, процесс которые могут быть дорогостоящими. Таким образом, производительность характеристики высказывания броска сопоставимы с характеристиками return.

Развертывание опций, которые nil не throw a Быстрая ошибка (которая может быть распространена) и не может быть обработана с помощью <Т29 > .

Вы должны использовать известные методы, такие как необязательное связывание, необязательное связывание, проверка на nil и т.д.

Ответ 2

этот "пояснительный" пример может помочь вам увидеть разницу между повышением исключения времени выполнения и выбросом ошибки E, соответствующей протоколу ErrorType.

struct E: ErrorType{}
func foo(bar:String?) throws {
    if let error = bar where error == "error" {
            throw E()
    }
    print(bar, "is valid parameter, but don't try to access bar.characters, it crash your code! (if bar == nil)")
    // here is everything OK 
    let bar = bar!
    // but here it crash!!
    _ = bar.characters
}

do {
    try foo("error")
    // next line is not accessible here ...
    try foo(nil)
} catch {
    print("\"error\" as parameter of foo() throws an ERROR!")
}
do {
    try foo(nil) // fatal error: unexpectedly found nil while unwrapping an Optional value
} catch {

}

он печатает

"error" as parameter of foo() throws an ERROR!
nil is valid parameter, but don't try to access bar.characters, it crash your code! (if bar == nil)
fatal error: unexpectedly found nil while unwrapping an Optional value

повышение исключений во время выполнения является фатальной ошибкой в ​​вашем коде.