我正在创建一个处理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
}
答案 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;含糊不清的
尽管有不同的错误消息(因为源根本不同),但问题完全相同,并且两个问题的解决方案是等效的。