我一直在玩Swift并发现当向下插入要插入字典的对象时,我会收到一个奇怪的警告: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而不是String,如果我继续使用as
,代码将退出并显示错误。如果我切换到使用as?
,那么代码将继续正常执行并跳过该语句(dict将保持为空)。但是,我不确定为什么这是更可取的。在我看来,我宁愿程序退出并出现错误,让我知道演员表不成功然后只是忽略错误的声明并继续执行。
根据文档,我应该使用强制形式“只有在你确定转发将永远成功时”。在这种情况下,我确信向下转换将永远成功,因为我知道test()
只能返回一个字符串,所以我认为这是强制形式的向下转换的完美情况。那么为什么编译器会给我一个警告?
答案 0 :(得分:44)
让我们仔细看看你的最后一行,并将其爆炸以查看发生了什么:
let temporaryAnyObject = test()
let temporaryString = temporaryAnyObject as String
dict["test"] = temporaryString
错误在第二行,您告诉编译器强制temporaryAnyObject
肯定是String
。代码仍将编译(假设您不将警告视为错误),但如果temporaryAnyObject
实际上不是String
,则会崩溃。
as
的工作方式,没有?
,基本上是说&#34;从现在开始,将此表达式的结果视为该类型,如果结果实际上是该类型,否则我们变得不一致,不能再运行了。
as?
的工作方式(使用?
)说&#34;从现在开始,将此表达式的结果视为该类型,如果结果实际上是该类型,否则该表达式的结果为nil
。
因此,在我上面展开的示例中,如果test()
确实返回String
,那么as
向下投射成功,而temporaryString
现在是String
。如果test()
没有返回String
,但是说Int
或其他任何未从字符串中继承的内容,那么as
将失败,代码将无法再继续跑步。
这是因为,作为完全控制的开发人员,您通过不放置可选的?
指示符告诉系统以这种方式运行。 as
命令特别意味着您不能容忍可选行为,并且您需要向下转换才能工作。
如果你放了?
,那么temporaryString
就是nil
,而第三行会简单地删除&#34; test&#34;字典中的键/值对。
这可能看起来很奇怪,但这只是因为这是许多语言的相反默认行为,比如Obj-C,默认情况下将所有内容视为可选,并依赖于您自己的检查和断言
编辑 - Swift 2更新
自Swift 2以来,强制的,可移动的向下转换运算符as
已被删除,并被替换为as!
,这是非常迅捷的。行为是一样的。
答案 1 :(得分:4)
您可以从两个角度解决此警告。 1.您返回的值2.您期望返回的类型。另一个答案谈到了第一个角度。我说的是第二个角度
这是因为您为可选返回强制解包和投放值。编译器就像,&#34; 如果你真的想强制转换所有选项,那么为什么不将预期的返回参数设为非可选 &# 34;
例如,如果你写了
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
但是在下一行,你说不,我不要!!!
编译器会发出警告:
对待强迫贬低对待&#39; T&#39;作为可选项永远不会产生&#39; nil&#39;
另一种方法是删除?
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
}
答案 2 :(得分:0)
几年前,似乎已经有关于此警告的错误信息打开…… https://bugs.swift.org/browse/SR-4209因此,即使在明显在做什么和正确的情况下,它也会显示出来。