Рассмотрение вынужденного подавления как необязательного никогда не приведет к "нулю"
Я играл со Свифтом и обнаружил, что когда я бросаю вниз объект, который нужно вставить в словарь, я получаю странное предупреждение: 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 }
В основном вы сказали себе (и компилятору), что я хочу безопасно обрабатывать
nil
s, но затем в самой следующей строке вы сказали: Нет, я не хочу!!!Компилятор выдаст предупреждение:
Рассмотрение принудительного понижения до '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 }