告诉泛型函数它的类型而不传递该类型的示例

时间:2016-02-19 02:35:35

标签: swift generics

我正在创建一个处理Firebase快照的通用函数,我发现泛型函数不知道要使用哪种类型,除非你通过在参数中提供它来明确告诉它类型。

所以我采用了一种非常丑陋的方法来创建一个空白,例如,User()并将其提供给此函数并且再也不会触及它。

更好的方法是什么?

   func handleSnapshot<T: FirebaseType>(snapshot: FDataSnapshot?, forType type: T) -> [T]? {
      guard let snapshot = snapshot, dictionaries = snapshot.value as? [NSObject: AnyObject] else { return nil }
      var objects = [T]()
      for (uid, dictionary) in dictionaries {
         let theUID = uid as? String ?? "No UID"
         guard let dictionary = dictionary as? [NSObject: AnyObject] else { return nil }

         let object = T(fromDictionary: dictionary, andUID: theUID)
         objects.append(object)
      }
      return objects
   }

2 个答案:

答案 0 :(得分:3)

传递类型对象而不是类型的实例。另外,andUID:是不好的风格。

func handleSnapshot<T: FirebaseType>(snapshot: FDataSnapshot?, forType type: T.Type) -> [T]? {
    guard let snapshot = snapshot, dictionaries = snapshot.value as? [NSObject: AnyObject] else { return nil }
    var objects = [T]()
    for (uid, dictionary) in dictionaries {
        let theUID = uid as? String ?? "No UID"
        guard let dictionary = dictionary as? [NSObject: AnyObject] else { return nil }

        if let object = T(fromDictionary: dictionary, uid: theUID) {
            objects.append(object)
        }
    }
    return objects
}

使用:

// Explicit type declaration is unnecessary but included for clarity.
let doodads: [Doodad]? = handleSnapshot(snapshot, forType: Doodad.self)

更新

另一种方法:将方法添加到协议扩展中的FirebaseType

extension FirebaseType {
    func arrayFromSnapshot(snapshot: FDataSnapshot?) -> [Self]? {
        guard let snapshot = snapshot, dictionaries = snapshot.value as? [NSObject: AnyObject] else { return nil }
        var objects = [Self]()
        for (uid, dictionary) in dictionaries {
            let theUID = uid as? String ?? "No UID"
            guard let dictionary = dictionary as? [NSObject: AnyObject] else { return nil }

            if let object = Self(fromDictionary: dictionary, uid: theUID) {
                objects.append(object)
            }
        }
        return objects
    }
}

使用:

let doodads = Doodad.arrayFromSnapshot(snapshot)

答案 1 :(得分:3)

根据上下文,可以推断出通用类型。

考虑以下简化示例:

protocol Bar {
    init(a: Int)
}

func foo<T: Bar>(arg1: Int) -> T {
    return T(a: arg1)
}

在这里,我们不会传递T类型的任何信息(除此之外,它符合Bar协议)

现在,给定一个符合协议的类,使用显式类型声明,我们可以调用该方法:

let x: Baz = foo(3)

我们甚至可以使用强制语法:

let y = foo(3) as Baz

或者,如果我们有一个带有显式类型的参数的函数,并且我们正在调用此方法调用:

func printIt(value: Baz) {
    print(value)
}

printIt(foo(5))

或者,如果我们的类具有我们正在设置的显式类型的属性:

class Z {
    var value: Baz
    init(arg: Baz) {
        value = arg
    }
}

let z = Z(arg: Baz(a: 0))
z.value = foo(4)

重要的是,如果您必须有某种方法来确定此信息。

值得注意的是,尽管确切的错误消息不同,但我们在此处看到错误:

func generic<T: Bar>(arg: Int) -> T {
    return T(a: arg)
}

let f = generic(2)
  

通用参数&#39; T&#39;无法推断

这个错误大致相当于我们在函数重载时遇到的同样问题:

func ambiguous(arg: Int) -> Int {
    return arg
}

func ambiguous(arg: Int) -> Double {
    return Double(arg)
}

let value = ambiguous(2)
  

模糊地使用&#39;含糊不清的

尽管有不同的错误消息(因为源根本不同),但问题完全相同,并且两个问题的解决方案是等效的。