以下代码在Swift 4.2(Xcode 10)中的行为不再与在Swift 4.1(Xcode 9.4.1)中的行为相同:
std::bit_cast
在Swift 4.1中,let key: String! = "key"
let dict: [AnyHashable:Any]? = ["key":"value"]
let val = dict?[key]
接收字典值(“值”),而在Swift 4.2中则为零。
如果我删除了明显地解包的可选(IUO),或者将字典声明为val
,那么问题就消失了,所以两者都
[String:Any]
和
let key: String = "key"
let dict: [AnyHashable:Any]? = ["key":"value"]
let val = dict?[key]
导致let key: String! = "key"
let dict: [String:Any]? = ["key":"value"]
let val = dict?[key]
最终包含字符串“ value”。
这是Swift 4.2中的预期行为,还是编译器错误?
请问一下,我有一个庞大的代码库,其中的键和字典都来自于Objective-C代码,该代码有点难以更改。因此,我想知道这种行为变化是否是永久的,应该开始更新使用此模式的代码中的许多位置,还是等到发布稳定的Xcode 10版本之后。
答案 0 :(得分:4)
有一个提案SE-0054,已在Swift 4.2中完全实现。过去,ImplicitlyUnwrappedOptional
类型的功能不同于Swift 4.2(现在,所有IUO都是Swift 4.2中的Optional
类型,而不是ImplicitlyUnwrappedOptional
)。
从提案(重点是我的):
如果可以显式对表达式进行强类型检查 可选类型,它将是。但是,类型检查器将退回到 必要时强制使用可选。这种行为的后果是 引用声明为T的值的任何表达式的结果! 将是T型还是T?型。例如,在下面 代码:
let x: Int! = 5 let y = x let z = x + 0
…x被声明为IUO,但是 因为y类型的初始值设定项可正确检查为可选项y 将绑定为Int类型。但是,z的初始化器不 用x声明为可选的类型检查(没有+的重载 需要一个可选的),因此编译器强制使用可选和类型 将初始化程序检查为Int。
在您的情况下,key
变量被推断为String?
类型,因此您仍然必须强制转换它。该代码将起作用:
let val = dict?[key!]
val
的值为Optional("value")
关于[String:Any]
起作用的原因,根据引号中强调的部分,String?
不能用在String
上,因此编译器将强制对其进行解包(必须使它会编译)。