可选类中的可选属性 VS 可选字典中的可选值

Posted

技术标签:

【中文标题】可选类中的可选属性 VS 可选字典中的可选值【英文标题】:Optional properties in optional classes VS Optional values in optional dictionaries 【发布时间】:2016-01-07 22:06:34 【问题描述】:

在尝试访问可选类中的可选属性的值时,我注意到一些有趣的行为,而尝试访问可选字典中的可选值的值。

在前一种情况下,您似乎只需要打开一次即可访问该值。但是,在后一种情况下,您必须解包两次才能访问该值。我想知道为什么会这样,并希望有人能给我一些见解!

以下是访问可选类中可选属性值的示例

class Cat
    var food : Food?


class Food
     var amount : Int?


var meowzer = Cat()
meowzer.food = Food()
meowzer.food?.amount = 10
var catFoodAmt = meowzer.food?.amount

print("\(catFoodAmt)")

if let catFoodCount = meowzer.food?.amount
    print("\(catFoodCount)")

第一个打印语句的结果是:

Optional(10)

第二条打印语句(展开后)的结果是:

10

下面是访问可选字典中可选值的值的示例

var dog : [String : Int?]?
dog = ["treat_count" : 10]

var dogTreatAmt = dog?["treat_count"]

print("\(dogTreatAmt)")

if let dogTreatCount = dog?["treat_count"] , dogTreatCountFinal = dogTreatCount

    print("\(dogTreatCount)")
    print("\(dogTreatCountFinal)")


第一个打印语句的结果是:

Optional(Optional(10))

第二个打印语句的结果(解包一次后)是:

Optional(10)

第三条打印语句的结果(解包两次后)是:

10

为什么在第二种情况下我需要解包两次才能访问所需的值,而不是第一种?

我的猜测是,如果我使用“treat_count”以外的键(例如“count”),那么该键的值将为零。但是,我无法找到 ios“规则”或更好的解释为什么会这样。任何帮助将不胜感激。

【问题讨论】:

[String : Int?] 是理论上的,实际上字典中的任何键和值都不能是nil 【参考方案1】:

区别在于Cat.food?.amount返回Int?,而Dictionary<String, Int?>.subscript(String)返回Int??

这是因为Dictionary.subscript<Key> 返回Element?,而Element 这里是Int?。因此,您将获得一个额外级别的 Optional。

可选链接只是在使用它的时候删除了一个额外的可选包装。它不会折叠所有选项。在一种情况下,您有两个,折叠到 1(对于一个 ?),在第二种情况下,您有三个,折叠到 2(对于一个 ?)。

正如 vadian 所暗示的,这将是一个疯狂的字典,所以它不太可能出现在好的 Swift 中,但它可以被推理。如果不是这样,您将丢失信息。

【讨论】:

嗯!我不知道 Dictionary.subscripty 返回了 Element?另外,感谢您提供有关可选链接的额外信息!【参考方案2】:

这实际上是有道理的:只需计算 ?s 的数量 :)。

对于您的第一个示例,该属性是可选的,在您的第二个示例中,您有一个可选字典,其键是字符串,值是可选整数。

因此,如果您想访问第二个示例的值,则必须解包字典,然后解包该字典中给定键的任何内容。

【讨论】:

【参考方案3】:

这是个好问题。让我们考虑一下 Dictionary 的类型定义:

struct Dictionary<Key : Hashable, Value>

以及下标函数的签名:

public subscript (key: Key) -> Value?

也可以认为是:

public subscript (key: Key) -> Optional<Value>

有了这个,让我们看看你的字典,它的类型是:

Dictionary<String, Int?>

或者更明确

Dictionary<String, Optional<Int>>

其中ValueOptional&lt;Int&gt; 类型,KeyString 类型

所以如果我们代入键,下标定义为:

subscript (key: String) -> Optional<Value>

如果我们将其替换为 Value,我们会得到您所看到的:

subscript (key: String) -> Optional<Optional<Int>

现在,让我们分解您的代码并将所有内容组合在一起:

var dogTreatAmt = dog?["treat_count"]

由于dog是可选的,所以不管你怎么调用它,结果也会被包裹在一个Optional中,我们暂时认为是Optional(FunctionReturn)

现在我们来看看FunctionReturn,它是下标函数。我们已经确定这将返回Optional&lt;Optional&lt;Int&gt;&gt;

这意味着您确实返回了Optional&lt;Optional&lt;Optional&lt;Int&gt;&gt;&gt;,但是正如 Rob Napier 所指出的, “可选链接在使用时删除了额外的可选包装”。

【讨论】:

以上是关于可选类中的可选属性 VS 可选字典中的可选值的主要内容,如果未能解决你的问题,请参考以下文章

Swift 中的可选值是啥?

Swift 中的可选类型错误:致命错误:在展开可选值时意外发现 nil

可选链式调用

Option可选值可选值

引用一个空的可选值

Swift16-可选链式调用