可选类型 'String??' 未展开

Optional Type 'String??' Not Unwrapped

"Value of optional type 'String??' not unwrapped; did you mean to use '!' or '?'?"-

我今天遇到了这个奇怪的编译器错误,由于 String 之后的 两个 问号,这完全令人困惑。

我有一个类型为 [String : String?] 的字典 s 和一个接受所有参数为 String? 的函数。具体来说(来自 5813 的 将用户选择的信息复制到字典中),我有以下详细版本:

func combine(firstname: String?, lastname: String?) {...}

var text = combine(s["kABPersonFirstNameProperty"], lastname: s["kABPersonLastNameProperty"])

我在第二行收到错误,我想知道为什么会这样。如果 s 中的值是 String? 类型,那不应该被 combine() 接受,因为它的参数应该是同一类型吗?那么,为什么我会收到此错误,我该如何解决呢?

它曾经是可选的,因为您的字典值是可选的。它又是可选的,因为 dictionary[key] returns 是可选的。所以你需要解包两次。

在操场上试试这个以了解问题(并查看可能的解决方案):

let oos: String?? = "Hello"
print(oos)

if let os = oos { // Make String?
    print(os)
    if let s = os { // Make ordinary String
        print(s)
    }
}

打印:

 Optional(Optional("Hello"))

 Optional("Hello")

 Hello

但是你也可以使用 if let 以外的其他方式来解包。例如:

 print(oos! ?? "n/a")

将强制解包一次然后打印内部字符串或 n/a 以防 nil...

Dictionary<T1, T2>[key]returns T2?。这是 return 零,以防密钥不存在。

所以如果 T2 是 String?, s[key] returns String?? 您不能将 String?? 作为 String?

你也可以像这样调用来解包并准备不存在的密钥

var text = combine(s["kABPersonFirstNameProperty"] ?? nil, lastname: s["kABPersonLastNameProperty"] ?? nil)

顺便说一下,下面的代码不会将值设置为 nil,而是会从字典中删除整个条目

s[key] = nil

如果您希望值为 nil 而不是删除条目,则必须这样做

s[key] = nil as String?

也许最简单的解决方案是使字典包含 String 而不是 String?。那么您就不会遇到其他解决方案中描述的展开问题。

或者您真的必须存储 String? 类型吗? 您想区分 'key exists but holds nil' 和 'key does not exist' 吗?