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

时间:2018-04-02 10:27:13

标签: swift

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

Any

请注意,如果我将字典指定为var aString: String! = "hello" var params : [String : Any] = [ "myString" : aString ] print(params) // This prints ["myString": Swift.ImplicitlyUnwrappedOptional<Swift.String>.some("hello")] 类型,它将被解包,但是当我需要[String : String]中的多个类型时,这没有用。

4 个答案:

答案 0 :(得分:10)

根据SE-0054规定的规则,IUO仅在需要其未打包类型的上下文中被强制解包。在您的情况下,IUO不需要强制解包,以便被强制转换为Any(因为Any可以代表任何值),所以它不是。

在这些Q&amp; As:

中更详细地讨论了这种行为

您在字典中最终得到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]

给你幻觉,强迫IUO在被强制解除Any时被解开。然而,这就是如何在Swift 4.0.3中打印IUO - 如果它们有一个值,那么它们将打印为该值,否则它们将打印为nil

var aString: String! = nil
var params : [String : Any] = [
  "myString" : aString
]
print(params)
// This prints ["myString": nil]

在Swift 4.1中更改的原因是ImplicitlyUnwrappedOptionalCustom(Debug)StringConvertible的一致性已被删除in this commit,以便在删除类型本身方面取得进展。所以现在使用Swift的默认打印机制(使用反射)打印ImplicitlyUnwrappedOptional值。

因此,在字典中,您会得到IUO的默认debugDescription,如下所示:

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

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

let aString: String! = "hello"
print(aString) // some("hello")

这是因为在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)

  // ...
}

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

但这只是暂时的; IUO类型目前(在Swift 4.1中)已被弃用,但它将在Swift 4.2中删除。编译器在很多地方内部使用IUO类型,花了quite a bit of work to remove。因此,在4.2中,您的词典中将包含实际 Optional值,其值将打印为Optional("hello")

答案 1 :(得分:0)

更改此行:

var params : [String : Any] = ["myString" : aString]

为:

var params : [String : String] = ["myString" : aString]

答案 2 :(得分:0)

定义类型

的字典时
let dictionary = [String:Any]()

你可以把任何东西放在这本词典中

喜欢

 dictionary["name"] = "xyz"

 dictionary["code"] = 123

let dictionary = [String:String]()

你只能输入一个字符串值

这就是为什么你在访问价值时必须解开价值的原因,因为它可能是任意的

答案 3 :(得分:0)

  • Any可以表示任何类型的实例,包括函数类型和可选类型。
  • AnyObject可以表示任何类类型的实例。

你的aString是一个不应该用于在属性Area中声明的实例对象,如果你将该行放在任何函数/实例function()中,那么它将完美地工作,因为它将是那么你的实例类型。

总之,你不能在Swift的属性区域中声明实例类型。

override func viewDidLoad() {
   let params : [String : Any] = ["myString": aString]
}

即使在物业区,您也不能这样做:

var aString: String! = "String"
var abc = aString

您必须abc = aString在任何Method()内完成工作。

希望它会对你有所帮助。