可选类中的可选属性 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这实际上是有道理的:只需计算 ?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>>
其中Value
是Optional<Int>
类型,Key
是String
类型
所以如果我们代入键,下标定义为:
subscript (key: String) -> Optional<Value>
如果我们将其替换为 Value
,我们会得到您所看到的:
subscript (key: String) -> Optional<Optional<Int>
现在,让我们分解您的代码并将所有内容组合在一起:
var dogTreatAmt = dog?["treat_count"]
由于dog
是可选的,所以不管你怎么调用它,结果也会被包裹在一个Optional中,我们暂时认为是Optional(FunctionReturn)
现在我们来看看FunctionReturn
,它是下标函数。我们已经确定这将返回Optional<Optional<Int>>
这意味着您确实返回了Optional<Optional<Optional<Int>>>
,但是正如 Rob Napier 所指出的,
“可选链接在使用时删除了额外的可选包装”。
【讨论】:
以上是关于可选类中的可选属性 VS 可选字典中的可选值的主要内容,如果未能解决你的问题,请参考以下文章