Swift4中使用泛型T.Type类时如何调用正确的构造器?
打造通用的数据库泛型读取函数
嘿,我懂你想做的事——不用为每个数据库表写重复的读取逻辑,一个泛型函数搞定所有对象的SQL映射,这个思路超棒!咱们来一步步把你的想法落地,解决调用时只能用特定对象的问题。
第一步:先定义一个映射协议
要让泛型函数能把SQL结果转成任意对象,首先得给所有对象定个“规矩”:它们必须知道怎么从SQL查询结果里创建自己。咱们定义一个协议:
protocol SQLMappable { init(from sqlResult: [String: Any]) throws }
这个协议要求每个遵守它的类,都实现一个从SQL字典(键是字段名,值是字段值)初始化自己的方法,这样泛型函数就能统一调用这个方法来创建对象了。
第二步:重构你的泛型函数
接下来修改你的readAll函数,给泛型T加上协议约束,这样函数里就能安全地调用初始化方法。同时,咱们把SQL查询的逻辑补全,还要处理可能的错误(比如查询失败、初始化失败):
func readAll<T: SQLMappable>(tableName: String, typeClass: T.Type) throws -> [T] { var results: [T] = [] // 1. 执行SQL查询,这里替换成你实际的SQL执行逻辑 let sqlQuery = "SELECT * FROM \(tableName)" guard let sqlResults = executeSQL(sqlQuery) else { throw DatabaseError.queryFailed } // 2. 把每条SQL结果转成T对象 for row in sqlResults { do { let object = try typeClass.init(from: row) results.append(object) } catch { throw DatabaseError.failedToMapObject(error) } } return results } // 辅助的错误定义,方便处理异常 enum DatabaseError: Error { case queryFailed case failedToMapObject(Error) } // 你实际的SQL执行函数,这里只是示例 func executeSQL(_ query: String) -> [[String: Any]]? { // 这里写你的数据库查询逻辑,返回查询到的行,每行是字段名到值的字典 return [] }
第三步:让你的对象类遵守协议
比如你有个User类对应users表,就让它实现SQLMappable协议:
class User: SQLMappable { let id: Int let name: String let email: String init(id: Int, name: String, email: String) { self.id = id self.name = name self.email = email } // 实现协议要求的初始化方法 required init(from sqlResult: [String: Any]) throws { guard let id = sqlResult["id"] as? Int, let name = sqlResult["name"] as? String, let email = sqlResult["email"] as? String else { throw MappingError.missingRequiredFields } self.id = id self.name = name self.email = email } } enum MappingError: Error { case missingRequiredFields }
第四步:正确调用泛型函数
现在你就可以用任意遵守SQLMappable的类型来调用这个函数了,不用再依赖特定对象:
do { // 读取users表,转成User数组 let users = try readAll(tableName: "users", typeClass: User.self) // 读取products表,转成Product数组(假设你有Product类且遵守协议) let products = try readAll(tableName: "products", typeClass: Product.self) } catch { print("读取数据失败:\(error)") }
这样就实现了你想要的真正泛型效果——同一个函数可以处理任何和数据库表对应的对象,只要对象遵守了映射协议就行。
内容的提问来源于stack exchange,提问作者Augusto
相关产品推荐
相关产品推荐

