Swift - 动态匹配类

时间:2015-08-15 10:44:02

标签: swift generics

我正在尝试使用以下签名在Dictionary上编写扩展方法:

func firstNonNilObjectForKey(keys: [Key], ofClass aClass: Any.Type = String.self) -> Value?

这是为了帮助我处理JSON词典,我经常需要第一个非null值,但有时JSON包含null本身作为值,在Cocoa中转换为NSNull

用法如下:

let dict: [String:AnyObject] = [...]
let myValue = dict.firstNonNilObjectForKey([ "key1", "key2" ]) as? String 

问题是实现性的 - 如何匹配班级:

if let value = self[key] {
    if value is aClass { ... } <--- error: aClass is not a type
    if let castedValue = value as? aClass { ... } <--- error: ditto

    let type = value.dynamicType
    if type == aClass { ... } <--- no error, but doesn't handle subclasses!

    // Cannot use value.isKindOfClass() since value may be Any
}

我想到了另一种选择:

func firstNonNilObjectForKey<ReturnValueType>(keys: [Key]) -> ReturnValueType?

允许实现为

if let value = self[key] as? ReturnValueType { ... }

但: - 这里我不能设置默认类型(我主要需要String.Type)。 - 我真的不确定如何调用它:

let value = dict.firstNonNilObjectForKey([ "key1", "key2" ]) as? String <--- error: Cannot invoke 'firstNonNilObjectForKey' with an argument list of type '([String])'
let value = dict.firstNonNilObjectForKey<String>([ ... ]) <--- error: Cannot explicitly specialize a generic function

我希望这不是重复,但这里大多数类似的问题只是处理你与已知类匹配的情况。

1 个答案:

答案 0 :(得分:3)

我不确定我是否完全符合要求,但是这样的东西可以为你工作吗?

extension Dictionary {

  func firstNonNilObjectForKey(keys: [Key]) -> String? {
    return self.firstNonNilObjectForKey(keys, ofClass: String.self)
  }

  func firstNonNilObjectForKey<T>(keys: [Key], ofClass aClass: T.Type) -> T? {
    for k in keys {
      if let v = self[k] as? T {
        return v
      }
    }
    return nil
  }

}

let dict = ["key1": 2, "key2": "Foo"]
let aString = dict.firstNonNilObjectForKey(["key1", "key2"]) // "Foo"
let anInt = dict.firstNonNilObjectForKey(["key1", "key2"], ofClass: Int.self) // 2

这里的主要问题是我使用重载而不是默认参数,这似乎与swift类型检查器相处得不好。