Swift 将字典值转换为类型

Swift cast dictionary value as type

我正在寻找如何将这段代码写成一行的最佳方法:

if (dictionary["Amoumt"] is Double) {
    amount = dictionary["Amount"] as Double
} else {
    amount = NSString(string: dictionary["Amount"] as String).doubleValue
}

我有 Dictionary<String, AnyObject>,我想从中解析值。我正在使用上面的代码,但行数太多。我想把它写成一行。类似于:

dictionary["Amount"].parseDouble()

使用此方法创建扩展没有问题:

func parseDouble() -> Double {
    if (self is Double) {
        return self as Double
    } else {
        return NSString(string:(self as String)).doubleValue
    }
}

但是我应该扩展哪种类型?接下来你能帮我用通用方法吗?所以我可以这样调用:

dictionary["Amount"].parse(Double)

这是一种很好的方法还是我应该用另一种方法来做?

最简单的压缩方法是使用 nil 合并运算符和可选的双精度数。这会尝试将该值转换为双精度值。如果成功,则解包,如果失败,则默认为第二个值,该值来自将 `dict[amount]' 转换为字符串并取其双精度值。

var amount: Double? = nil

let dict: [String: AnyObject] = ["amount" : "1.2"]

amount = (dict["amount"] as? Double) ?? NSString(string: dict["amount"] as! String).doubleValue

并实现你的功能:

func getDouble(obj: AnyObject) -> Double {
    return (obj as? Double) ?? NSString(string: obj as! String).doubleValue
}

然后您使用 getDouble(dict["amount"]) 调用它。在我看来,这样的扩展可能有点矫枉过正。

也许您正在寻找这种扩展:

extension Dictionary{

    func parseDouble(key:Key) -> Double {

        let result = self[key]

        if (result is Double) {
            return result as Double
        } else {
            return NSString(string:(result as String)).doubleValue
        }
    }
}

并使用此获取键的值:

var doubleValue = dictionary.parseDouble("amount")

还有一个通用函数

extension Dictionary{

    func parse<T>(key:Key) -> T? {

        let result = self[key]

        if (result is T) {
            return result as? T
        }

        return nil
    }
}

var doubleValue:Double? = myDistionary.parse("someKeyForDouble")

var stringValue:String? = myDistionary.parse("someKeyForString")

如果您想要扩展,理论上最好的放置位置是 AnyObject – 因为它是您要转换的 AnyObject

但是AnyObject实际上是一个协议,所以你不能扩展它。

我不建议将其作为 Dictionary 的扩展 – 将类型强制转换为双精度与字典没有任何关系。

所以最好的方法是将其作为免费功能而不是扩展来实现:

func getDouble(obj: AnyObject?) -> Double {
    return (obj as? Double) ?? (obj as? NSString)?.doubleValue ?? 0
}
asDouble(dictionary["Amount"])

请注意,如果您向该函数传递的函数既不是双精度型也不是字符串型,那么该函数是安全的。如果您传入其他内容,使用 as! 而不是 as? 的其他解决方案将在运行时崩溃。

你可以争辩说它应该 return 一个可选的,如果该值不能转换为双精度,则为 nil。这就是 String.toInt() 所做的。不幸的是,NSString.doubleValue 的局限性在于它不会这样做——它默认为零——所以你不能将这两种方法结合起来。

您可以按原样使用 AnyObject。尝试:

var dictionary:[String:AnyObject] = [
    "foo": 4.21,    // NSNumber
    "bar": "42.5",  // NSString
    "baz": [1,2,3], // NSArray
]

let foo = dictionary["foo"]?.doubleValue ?? 0 // -> 4.21
let bar = dictionary["bar"]?.doubleValue ?? 0 // -> 42.5
let baz = dictionary["baz"]?.doubleValue ?? 0 // -> 0.0

之所以有效,是因为 NSNumberNSString 都有 .doubleValue 属性。 另一方面,NSArray 没有 属性,在这种情况下它 returns nil.

the document所述:

You can also call any Objective-C method and access any property without casting to a more specific class type. This includes Objective-C compatible methods marked with the @objc attribute.