在Swift中为可选字典赋值

Gar*_*ght 10 dictionary swift

我在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"
}
Run Code Online (Sandbox Code Playgroud)

我已经玩了很多,试图弄清楚我可能会遗漏什么,但似乎没有任何东西使这个代码按预期工作,使得字典不是可选的.我错过了什么?

我能得到的最接近的是以下,但当然这很荒谬.

var foo:Dictionary<String, String>?

if (foo == nil) {
    foo = ["bar": "baz"]
}
else if var foofoo = foo {
    foofoo["qux"] = "quux"
    foo = foofoo
}
Run Code Online (Sandbox Code Playgroud)

mat*_*att 31

当您意识到可选字典不是字典时,灯泡时刻就会出现.一个可选的东西不是那个东西!这是一个可选的!! 这就是全部.可选本身就是一种类型.一个可选项只是一个枚举,包含可能的案例nil和一些值.包装的值是一个完全不同的对象,存储在里面.

所以任何东西都不会像那种东西那样.不是那个东西!这只是一个选择.解决问题的唯一方法是解开它.

隐式解包的Optional也是如此; 不同之处仅在于隐式展开的Optional愿意"自动"生成(公开)包装值.但它实际上仍然是包装好的.并且,正如布莱恩·陈所观察到的那样,它是不可改变地包裹着的; 可选项只是为您举办 - 它没有给您一个可以玩的地方.


Bry*_*hen 7

你可以使用这段代码

if var foofoo = foo {
    foofoo["qux"] = "quux"
    foo = foofoo
} else {
    foo = ["bar": "baz"]    
}
Run Code Online (Sandbox Code Playgroud)

用这个代码

var foo:Dictionary<String, String>? = Dictionary()
foo[""]=""

error: 'Dictionary<String, String>?' does not have a member named 'subscript'
foo[""]=""
^
Run Code Online (Sandbox Code Playgroud)

错误消息对我Dictionary<String, String>?没有实现subscript方法是有意义的,所以你需要在能够使用之前解开它subscript.

在可选上调用方法的一种方法是使用!ie foo![""],但是......

var foo:Dictionary<String, String>? = Dictionary()
foo![""]=""

error: could not find member 'subscript'
foo![""]=""
~~~~~~~~^~~
Run Code Online (Sandbox Code Playgroud)

var foo:Dictionary<String, String>? = Dictionary()
foo![""]
Run Code Online (Sandbox Code Playgroud)

作品


有趣的是这些代码无法编译

var foo:Dictionary<String, String>! = Dictionary() // Implicitly unwrapped optional
foo[""]=""

error: could not find an overload for 'subscript' that accepts the supplied arguments
foo[""]=""
~~~~~~~^~~
Run Code Online (Sandbox Code Playgroud)
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: "")
^   ~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

最后一条错误信息最有意思,它是说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
Run Code Online (Sandbox Code Playgroud)

这引出了另一个问题,为什么ArrayDictionary价值类型(结构)?对面NSArrayNSDictionary哪个是参考类型(类)