Рассмотрение вынужденного подавления как необязательного никогда не приведет к "нулю"
Я играл со Свифтом и обнаружил, что когда я бросаю вниз объект, который нужно вставить в словарь, я получаю странное предупреждение: Treating a forced downcast to 'String' as optional will never produce 'nil'. Если я заменю as на as?, то предупреждение исчезнет.
func test() -> AnyObject! {
return "Hi!"
}
var dict = Dictionary<String,String>()
dict["test"]=test() as String
В документации Apple говорится следующее
, потому что приведения типов может подвести, типа оператор приведения поставляется в двух различных формах. Необязательная форма
as?возвращает необязательное значение типа, который вы пытаетесь понизить. Принудительная форма,as, пытается опустить и принудительно разворачивает результат как одно сложное действие.
Мне непонятно, почему здесь правильно использовать as? вместо as. Некоторые тесты показывают, что если я изменю test (), чтобы вернуть Int вместо строки, код завершится с ошибкой, если я продолжу использовать as. Если я переключусь на using as?, то код продолжит выполнение нормально и пропустит эту инструкцию (dict останется пустым). Однако я не уверен, почему это предпочтительнее. В моем мнение, я бы предпочел, чтобы программа вышла с ошибкой и дала мне знать, что приведение было неудачным, а затем просто проигнорировала ошибочное утверждение и продолжила выполнение.
test() может вернуть только строку, поэтому я бы предположил, что это идеальная ситуация для принудительной формы понижения. Так зачем компилятор выдает мне предупреждение?2 ответа:
Давайте поближе посмотрим на вашу последнюю строку и взорвем ее, чтобы увидеть, что происходит:
let temporaryAnyObject = test() let temporaryString = temporaryAnyObject as String dict["test"] = temporaryStringОшибка находится во второй строке, где вы говорите компилятору принудительно, что
temporaryAnyObjectопределенно являетсяString. Код все равно будет компилироваться (при условии, что вы не рассматриваете предупреждения как ошибки), но произойдет сбой, еслиtemporaryAnyObjectна самом деле не являетсяString.Способ работы
as, Без?, в основном говорит: "отныне рассматривайте результат этого выражения как этот тип, если результат на самом деле именно такого типа, иначе мы становимся непоследовательными и больше не можем бежать.Способ работы
as?(с?) гласит: "отныне рассматривайте результат этого выражения как этот тип, если результат действительно относится к этому типу, иначе результатом этого выражения будетnil.Итак, в моем взорванном примере выше, если
test()возвращает aString, тоasпонижается успешно, иtemporaryStringтеперь являетсяString. Еслиtest()не возвращает aString, но говорит anIntили что-нибудь еще иначе не подкласс из строки, тоasзавершается ошибкой, и код больше не может продолжать работать.Это происходит потому, что, как разработчик в полном контроле, вы сказали системе вести себя таким образом, не ставя необязательный индикатор
?. Командаasконкретно означает, что вы не допускаете необязательного поведения и требуете, чтобы он работал.Если бы вы поставили
Это может показаться странным, но это только потому, что это противоположное поведение по умолчанию многих языков, таких как Obj-C, которые рассматривают все как необязательное по умолчанию и полагаются на вас, чтобы разместить свои собственные проверки и утверждения.?, тоtemporaryStringбыло быnil, а третья строка просто удалила бы" тестовый " ключ / значение пара из словаря.Edit-Swift 2 Update
Начиная со Swift 2, принудительный, отказоустойчивый оператор понижения
asбыл удален и заменен наas!, который намного быстрее. Поведение то же самое.
Вы можете решить эту проблему с двух точек зрения. 1. Значение, которое вы возвращаете 2. Тип, который вы ожидаете вернуть. Другой ответ говорит о 1-м угле. Я говорю о 2-м угле
Это происходит потому, что вы возвращаете принудительно развернутое и приведенное значение для необязательного. Компилятор такой: "Если вы действительно хотите просто принудительно привести все опционные параметры, то почему бы просто не сделать ожидаемый возвращаемый параметр равным необязательный"
Например, если вы написали
func returnSomething<T> -> T?{ // I'm an optional, I can handle nils SAFELY and won't crash. return UIViewController as! T // will never return a safe nil, will just CRASH }В основном вы сказали себе (и компилятору), что я хочу безопасно обрабатывать
nils, но затем в самой следующей строке вы сказали: Нет, я не хочу!!!Компилятор выдаст предупреждение:
Рассмотрение принудительного понижения до 'T' как необязательного никогда не приведет к 'nil'
Альтернативой является удаление
?func returnSomething<T>() -> T{ // I can't handle nils return UIViewController() as! T // I will crash on nils }
С учетом сказанного, вероятно, лучший способ-не использовать силу бросьте и просто сделайте:
func returnSomething<T>() -> T?{ // I can handle nils return UIViewController() as? T // I won't crash on nils }