使用filter对比数组遇类型转换错误,Playground无此问题求排查
Swift数组filter对比时报类型不匹配错误的解决方法
问题场景
从API拉取用户数据后,与本地数据库的用户数组对比,调用filterArrays方法时触发错误。相同代码在Playground中可正常运行,但项目代码报错,错误提示:
无法将类型 'Users' 转换为预期的参数类型 '(Users) throws -> Bool'
相关代码:
网络请求获取用户的方法
func getUsersNetworking() { getUsersDatabase() manager.getUsers { [weak self] results in guard let self = self else { return } switch results { case .success(let users): // 传递数据进行对比 self.filterArrays(currentUsersFromDB: self.databaseUsers, newUsersFromNet: users) // 与问题无关的代码 self.getUsersDatabase() case .failure(let error): print(error.localizedDescription) } } }
报错的filterArrays方法
func filterArrays(currentUsersFromDB: [Users], newUsersFromNet: [Users]) { let users = newUsersFromNet.filter { currentUsersFromDB.contains($0)} // 错误发生在此行! var array: [Users] = [] array.append(contentsOf: users) database.saveUsersToDB(users: array) }
问题原因
错误根源在于Array.contains(_:)方法的调用:
- 默认的
contains(_:)要求数组元素遵循Equatable协议,用来判断两个实例是否相等。 - 如果你的
Users类型(结构体/类)没有实现Equatable协议,编译器会找不到匹配的contains(_:)方法,转而尝试调用另一个重载contains(where:)——这个方法需要传入一个闭包(Users) throws -> Bool,但你传入的$0是Users实例,类型完全不匹配,因此触发报错。 - Playground能运行,大概率是因为你在Playground中给
Users实现了Equatable,但项目里遗漏了这一步。
解决方案
方案1:给Users类型实现Equatable协议
如果Users的所有存储属性都遵循Equatable,可以直接让编译器自动合成实现:
// 结构体示例 struct Users: Equatable { var id: Int var name: String // 其他属性 } // 类示例(需要手动实现==方法) class Users: Equatable { var id: Int var name: String init(id: Int, name: String) { self.id = id self.name = name } static func == (lhs: Users, rhs: Users) -> Bool { // 用唯一标识(比如id)判断用户是否相同 return lhs.id == rhs.id } }
方案2:改用contains(where:)显式传闭包
如果不想给Users实现Equatable,可以直接在contains里传入判断闭包,明确指定相等逻辑:
func filterArrays(currentUsersFromDB: [Users], newUsersFromNet: [Users]) { // 改用contains(where:),通过id判断用户是否存在于本地数组 let users = newUsersFromNet.filter { newUser in currentUsersFromDB.contains { $0.id == newUser.id } } var array: [Users] = [] array.append(contentsOf: users) database.saveUsersToDB(users: array) }
内容的提问来源于stack exchange,提问作者chAOS
相关产品推荐
相关产品推荐

