如何编写处理可选值的字典扩展

Posted

技术标签:

【中文标题】如何编写处理可选值的字典扩展【英文标题】:How to write Dictionary extension that handles optional values 【发布时间】:2015-01-03 16:22:22 【问题描述】:

我正在尝试实现Dictionary 扩展,并且我想处理可选值。但无论我做什么,如果我在 [String: String?] 字典上使用我的方法,它就无法选择性地绑定该值。你如何为一个优雅地处理可选值的字典编写一个扩展?


考虑以下扩展:

extension Dictionary 
    func someMethod() 
        for (key, value) in self 
            if let valueString = value as? String 
                println("  \(key) = \(valueString)")
             else 
                println("  \(key) = \(value) cannot be cast to `String`")
            
        
    

所以考虑下面的代码:

let dictionary: [String: AnyObject?] = ["foo": "bar"]
dictionary.someMethod()

它奇怪地报告

foo = Optional(bar) cannot be cast to `String`

我可以编写一个非扩展方法来处理具有可选值的字典参数,但不知道如何将其作为Dictionary 的扩展。

【问题讨论】:

我可以解释为什么它不像你预期的那样工作。当应用于 Optional 时,asisas?==(以及其他比较器)具有特殊含义:它们应用于事物包装。 if let valueString = value as? String 没有按照您的预期执行的原因是,在编译时我们不知道 value 一个 Optional,因此我们不使用特殊含义as 应用于 Optional。我们尝试将 Optional itself 转换为 String,当然失败了;你不能将 Optional itself 投射到任何东西上。 正如您自己所说,我相信,Swift 似乎邀请使用实例方法,但实际的力量在于***全局函数,因为它们允许您构建一个通用约束,只允许通过网格的正确类型,因为它是。字典是泛型的,你不能给泛型添加更多的约束,所以你永远不能用扩展中的实例方法来做到这一点。 【参考方案1】:

你可以通过反射来做到这一点。不需要比现有更多的代码:

extension Dictionary

    func someMethod()
    
        for (key, value) in self
        
            var valueRef = _reflect(value)

            while valueRef.disposition == .Optional && valueRef.count > 0 && valueRef[0].0 == "Some"
            
                valueRef = valueRef[0].1
            

            if let valueString: String = valueRef.value as? String
            
                print("  \(key) = \(valueString)")
            
            else
            
                print("  \(key) = \(value) cannot be cast to `String`")
            
        
    


let dictionary: [String : AnyObject?] = ["foo" : "bar"]
dictionary.someMethod()

返回

foo = bar

let dictionary: [String : AnyObject?] = ["foo" : nil]
dictionary.someMethod()

返回

foo = nil cannot be cast to `String`

let dictionary: [String : AnyObject?] = ["foo" : UIViewController()]
dictionary.someMethod()

返回

foo = Optional(<UIViewController: 0x7fee7e819870>) cannot be cast to `String`

【讨论】:

【参考方案2】:

当我插入 ':String?' 时我没有遇到任何问题valueString 之后如下图:

extension Dictionary 
    func someMethod() -> Bool 
        for (key, value) in self 
            if let valueString:String? = value as? String 
                println("  \(key) = \(valueString)")
             else 
                println("  \(key) = \(value) cannot be cast to `String`")
                return false
            
        
        return true
    


func doSomething() 
    let dictionary: [String: AnyObject?] = ["foo": "bar"]
    if dictionary.someMethod() 
        println("no problems")
     else 
        println("casting issues")
    

【讨论】:

有趣。当我这样做时,它不会失败并落入“无法转换”(即它返回true,但valueString 始终是nil,即使提供了一个值。

以上是关于如何编写处理可选值的字典扩展的主要内容,如果未能解决你的问题,请参考以下文章

组成必需值和可选值的期货

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

由于该应用程序崩溃,字典得到 nil 值。在展开可选值时意外发现 nil

如何在展开可选值时调试“nil 的致命错误”?

用返回非可选值的计算属性覆盖返回可选值的计算属性

Swift 中的可选值是啥?