考虑以下涉及 nil coalescing operator ??
的示例:
let mysteryInc = ["Fred": "Jones", "Scooby-Doo": nil]
let lastname = mysteryInc["Scooby-Doo"] ?? "no last name"
print(lastname == nil) // true
如上一个print
语句所示, nil合并运算符的结果为nil
。
如果 nil coalescing operator 应该打开 Optional ,为什么它会返回nil
?
答案 0 :(得分:10)
要查看此处发生了什么,请将字典指定为常量:
let name = mysteryInc["Scooby-Doo"]
print(type(of: name))
输出:
Optional<Optional<String>>
因此,name
是双重可选,String??
。
当应用 nil coalescing operator 时,它将展开外部 Optional 并留下Optional<String>
(又名String?
)。在问题的示例中,Swift将字符串文字"no last name"
视为类型String?
,以便可以应用??
。
如果您检查name
的值,您会发现它是Optional(nil)
。所有词典查找都会返回 Optionals ,因为键可能不存在(在这种情况下,它们会返回nil
)。在这种情况下,mysteryInc
字典的类型为[String: String?]
。与"Scooby-Doo"
对应的值为nil
,然后将其包含在可选中(因为字典查找)成为Optional(nil)
。
最后,值Optional(nil)
由??
解包。自Optional(nil) != nil
起,Swift解包Optional(nil)
并返回nil
,而不是返回预期的"no last name"
。
这就是你可以从 nil coalescing operator 获得nil
的方法。它解开了 Optional ;恰好是 Optional 中的nil
。
正如@LeoDabus在评论中指出的那样,处理这种情况的正确方法是在应用 nil coalescing operator 有条件地将名称转换为String
>:
let lastname = mysteryInc["Scooby-Doo"] as? String ?? "no last name"
实际上,最好避免将 Optionals 作为词典的值,因为@Sulthan提出了这个原因:
mysteryInc["Fred"] = nil
做了什么?
将nil
分配给字典条目会从字典中删除该条目,因此mysteryInc["Fred"] = nil
不会将Optional("Jones")
替换为nil
,而是删除{{1}完全进入。要将"Fred"
留在字典中并使其姓氏为"Fred"
,您需要指定nil
或mysteryInc["Fred"] = Optional(nil)
。