我在Swift中使用可选字典找到了一些令人惊讶的行为。
var foo:Dictionary<String, String>?
if (foo == nil) {
foo = ["bar": "baz"]
}
else {
// Following line errors with "'Dictionary<String, String>?' does
// not have a member named 'subscript'"
foo["qux"] = "quux"
}
我已经玩了很多,试图弄清楚我可能会遗漏什么,但似乎没有任何东西使这段代码按预期工作,使得字典不是可选的。我错过了什么?
我能得到的最接近的是以下,但这当然是荒谬的。
var foo:Dictionary<String, String>?
if (foo == nil) {
foo = ["bar": "baz"]
}
else if var foofoo = foo {
foofoo["qux"] = "quux"
foo = foofoo
}
答案 0 :(得分:31)
灯泡时刻就是你意识到一个可选词典不是一个词典。一个可选的东西不是那个东西!这是一个可选的!!这就是全部。可选本身就是一种类型。一个可选项只是一个枚举,包含可能的案例nil和一些值。包装的值是一个完全不同的对象,存储在里面。
因此,一个可选的任何不会像那种东西那样行事。不是那个东西!这只是一个选择。解决问题的唯一方法就是解开它。
隐式解包的Optional也是如此;区别在于隐式展开的Optional愿意自动生成(暴露)包装的值&#34;自动&#34;。但它实际上仍然是包装好的。并且,正如布莱恩·陈所观察到的那样,它是不可改变地包裹着的; “可选”只是为您举办 - 它没有给您一个可以玩的地方。
答案 1 :(得分:7)
您可以使用此代码
if var foofoo = foo {
foofoo["qux"] = "quux"
foo = foofoo
} else {
foo = ["bar": "baz"]
}
使用此代码
var foo:Dictionary<String, String>? = Dictionary()
foo[""]=""
error: 'Dictionary<String, String>?' does not have a member named 'subscript'
foo[""]=""
^
错误消息让我觉得Dictionary<String, String>?
没有实现subscript
方法,因此您需要在能够使用subscript
之前将其解包。
在可选项上调用方法的一种方法是使用!
,即foo![""]
,但是......
var foo:Dictionary<String, String>? = Dictionary()
foo![""]=""
error: could not find member 'subscript'
foo![""]=""
~~~~~~~~^~~
,而
var foo:Dictionary<String, String>? = Dictionary()
foo![""]
作品
有趣的是这些代码无法编译
var foo:Dictionary<String, String>! = Dictionary() // Implicitly unwrapped optional
foo[""]=""
error: could not find an overload for 'subscript' that accepts the supplied arguments
foo[""]=""
~~~~~~~^~~
var foo:Dictionary<String, String>! = Dictionary() // Implicitly unwrapped optional
foo.updateValue("", forKey: "")
immutable value of type 'Dictionary<String, String>' only has mutating members named 'updateValue'
foo.updateValue("", forKey: "")
^ ~~~~~~~~~~~
最后一条错误消息最有趣,它是说Dictionary
是不可变的,因此无法调用updateValue(forKey:)
(变异方法)
所以发生的事情可能是Optional<>
将Dictionary
存储为不可变对象(let
)。因此,即使Optional<>
它是可变的,您也无法直接修改基础Dictionary
对象(无需重新分配Optional
对象)
并且此代码有效
class MyDict
{
var dict:Dictionary<String, String> = [:]
subscript(s: String) -> String? {
get {
return dict[s]
}
set {
dict[s] = newValue
}
}
}
var foo:MyDict? = MyDict()
foo!["a"] = "b" // this is how to call subscript of optional object
这引出了另一个问题,为什么Array
和Dictionary
是值类型(struct)?与NSArray
和NSDictionary
相反,它们是引用类型(类)
答案 2 :(得分:0)
这是因为您的词典是可选的。如果它为零,则无法为其添加条目。
你可以这样做:
var dict: [String : String]?
if let dict = dict {
dict["key"] = "value" // add a value to an existing dictionary
} else {
dict = ["key" : "value"] // create a dictionary with this value in it
}
或者,如果给你一个可选字典,例如HTTPHeaders - 在AlamoFire中是一个[String:String]字典 - 并且你想要添加一个值,如果它是非零的,或者创建它有了这个值,如果它没有,你可以这样做:
let headers: HTTPHeaders? // this is an input parameter in a function for example
var customHeaders: HTTPHeaders = headers ?? [:] // nil coalescing
customHeaders["key"] = "value"
答案 3 :(得分:0)
我为Swift 3.1尝试了这个,它起作用了:
if (myDict?[key] = value) == nil {
myDict = [key: value]
}