为什么nil合并算子?返回零?

vac*_*ama 5 optional swift

请考虑以下涉及nil合并运算符的 示例??:

let mysteryInc = ["Fred": "Jones", "Scooby-Doo": nil]

let lastname = mysteryInc["Scooby-Doo"] ?? "no last name"

print(lastname == nil)  // true
Run Code Online (Sandbox Code Playgroud)

如最后一个print语句所示,nil合并运算符的结果是nil.

如果nil coalescing运算符应该解包一个Optional,为什么它会返回nil

vac*_*ama 10

要查看此处发生了什么,请将字典指定为常量:

let name = mysteryInc["Scooby-Doo"]
print(type(of: name))
Run Code Online (Sandbox Code Playgroud)

输出:

Optional<Optional<String>>
Run Code Online (Sandbox Code Playgroud)

所以,name是一个双重可选,一个String??.

当应用nil coalescing运算符时,它会解包外部Optional并留下Optional<String>(aka String?).在问题的示例中,Swift将String文字"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零合并算子中获得的.它解开了Optional ; 恰好nil是那个Optional的内部.


正如@LeoDabus在评论中指出的那样,处理这种情况的正确方法是在应用nil合并运算符之前有条件地转换名称:String

let lastname = mysteryInc["Scooby-Doo"] as? String ?? "no last name"
Run Code Online (Sandbox Code Playgroud)

实际上,最好避免将Optionals作为字典的值,因为@Sulthan引发了:

怎么mysteryInc["Fred"] = nil办?

分配nil到字典条目中删除从字典中的条目,所以mysteryInc["Fred"] = nil不会替换Optional("Jones")nil,它消除了"Fred"完全的条目.要留下"Fred"字典并使其姓氏nil,您需要指定mysteryInc["Fred"] = Optional(nil)mysteryInc.updateValue(nil, forKey: "Fred").

  • 你需要首先转换为字符串,然后使用nil合并运算符`as?字串?"没有姓"" (2认同)