为什么隐式解包可选不在字典中解包[String:Any]

Tom*_*you 4 swift

如果我在我的类中声明了一个隐式解包的可选项,然后我在Dictionary类型中引用[String : Any]它,它就不会被解包.为什么是这样?为什么Any,这不是可选的,不强迫它打开?

var aString: String! = "hello"
var params : [String : Any] = [
    "myString" : aString
]
print(params)
// This prints ["myString": Swift.ImplicitlyUnwrappedOptional<Swift.String>.some("hello")]
Run Code Online (Sandbox Code Playgroud)

请注意,如果我将字典指定为类型[String : String],它将被解包,但这对于我需要多个类型时没有用Dictionary.

Ham*_*ish 10

根据SE-0054规定的规则,IUO仅在要求其未包装类型的环境中被强行打开.在您的情况下,IUO不需要强制解包以便被强制Any(Any可以表示任何值),所以它不是.

在这些问答中更详细地讨论了这种行为:

您最终ImplicitlyUnwrappedOptional在字典中输入值的事实是在最新的Swift快照中删除的遗留行为,将来您将最终得到一个Optional值(因为IUO不再是类型).

然而,这里要注意的一件重要事情(我肯定会绊倒人们)是IUO 的打印在4.1中发生了变化.

在Swift 4.0.3中,您的示例打印如下:

var aString: String! = "hello"
var params : [String : Any] = [
  "myString" : aString
]
print(params)
// This prints ["myString": hello]
Run Code Online (Sandbox Code Playgroud)

给你的幻觉是IUO在被胁迫时被强行打开Any.然而,这只是如何在Swift 4.0.3中打印IUO - 如果它们有一个值,那么它们将打印为该值,否则它们将打印为nil:

var aString: String! = nil
var params : [String : Any] = [
  "myString" : aString
]
print(params)
// This prints ["myString": nil]
Run Code Online (Sandbox Code Playgroud)

之所以在Swift 4.1中改变,是因为在此提交中删除了ImplicitlyUnwrappedOptional符合性,以便在删除类型本身方面取得进展.所以现在使用Swift的默认打印机制(使用反射)打印值.Custom(Debug)StringConvertibleImplicitlyUnwrappedOptional

因此,在字典中,您将获得IUO的默认值debugDescription,如下所示:

let aString: String! = "hello"
let params : [String : Any] = [
  "myString" : aString
]
print(params)
// This prints ["myString": Swift.ImplicitlyUnwrappedOptional<Swift.String>.some("hello")]
Run Code Online (Sandbox Code Playgroud)

如果你自己打印它,你会得到它的默认值description,如下所示:

let aString: String! = "hello"
print(aString) // some("hello")
Run Code Online (Sandbox Code Playgroud)

这是因为在Swift 4.1中,ImplicitlyUnwrappedOptional类型的实现方式Optional与包含两种情况的枚举相同:

public enum ImplicitlyUnwrappedOptional<Wrapped> : ExpressibleByNilLiteral {
  // The compiler has special knowledge of the existence of
  // `ImplicitlyUnwrappedOptional<Wrapped>`, but always interacts with it using
  // the library intrinsics below.

  /// The absence of a value. Typically written using the nil literal, `nil`.
  case none

  /// The presence of a value, stored as `Wrapped`.
  case some(Wrapped)

  // ...
}
Run Code Online (Sandbox Code Playgroud)

对于具有有效负载值的IUO,因此Swift的默认反射将打印为some包含包装值的情况.

但这只是暂时的; IUO类型目前(在Swift 4.1中)已被弃用,但它将在Swift 4.2中删除.编译器在很多地方内部使用IUO类型,这需要相当多的工作来删除.因此,在4.2中,您将在字典中显示实际 Optional值,这些值将打印出来Optional("hello").