0

以下代码在 Swift 4.2 (Xcode 10) 中的行为不再与在 Swift 4.1 (Xcode 9.4.1) 中的行为相同:

let key: String! = "key"
let dict: [AnyHashable:Any]? = ["key":"value"]
let val = dict?[key]

在 Swift 4.1 中,val接收字典值(“value”),而在 Swift 4.2 中它是 nil。

如果我删除隐式展开的可选(IUO)或将字典声明为,问题就会消失[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]

导致val最终持有字符串“value”。

这是 Swift 4.2 中的预期行为,还是编译器错误?

问我有一个庞大的代码库,其中键和字典都来自Objective-C代码,这有点难以改变。所以我想知道这种行为变化是否是永久性的,我应该开始更新代码中使用这种模式的许多地方,或者等到 Xcode 10 的稳定版本发布。

4

1 回答 1

4

有一个提案SE-0054已在 Swift 4.2 中完全实现。过去,有一种类型ImplicitlyUnwrappedOptional与 Swift 4.2 的功能不同(现在所有的 IUO 都是OptionalSwift 4.2 中的类型,而不是ImplicitlyUnwrappedOptional)。

从提案(强调我的):

如果表达式可以使用强可选类型进行显式类型检查,它将是。但是,如果需要,类型检查器将退回到强制可选的。此行为的效果是任何引用声明为 T! 的值的表达式的结果。要么有 T 型,要么有 T 型?例如,在以下代码中:

let x: Int! = 5
let y = x
let z = x + 0

... x 被声明为 IUO,但由于 y 类型的初始化程序正确检查为可选,y 将被绑定为 Int? 类型。但是,z 的初始化程序不会在将 x 声明为可选项的情况下进行类型检查(没有 + 的重载接受可选项),因此编译器会强制使用可选项,并将初始化程序的类型检查为 Int。

在您的情况下,key变量被推断为 type String?,因此您仍然必须强制转换它。此代码将起作用:

let val = dict?[key!]

val有价值Optional("value")

至于为什么[String:Any]有效,根据引用中强调的部分,String?can't be used on String,所以编译器会强制解包(必须让它编译)。

于 2018-08-20T12:25:54.113 回答