【问题标题】: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 似乎邀请使用实例方法,但实际的力量在于顶级全局函数,因为它们允许您构建一个通用约束,只允许通过网格的正确类型,因为它是。字典是泛型的,你不能给泛型添加更多的约束,所以你永远不能用扩展中的实例方法来做到这一点。

标签: swift swift-dictionary


【解决方案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,即使提供了一个值。
    猜你喜欢
    • 2023-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-16
    • 1970-01-01
    相关资源
    最近更新 更多