Swift 4.2升级后嵌套filter出现'Ambiguous use of filter'错误的解决
Swift 4.2: 解决嵌套filter导致的'Ambiguous use of filter'错误
问题场景
我在维护其他开发者的代码,之前已经顺利迁移到Swift 4,但升级到Swift 4.2后碰到了**'Ambiguous use of filter'**错误。大部分错误我通过拆分复杂语句修复了,但遇到一处嵌套filter的场景不知道怎么处理,完整函数如下:
func validateSubmission(_ submissionId: Int) -> ([EntryModel]) { let realm = try! Realm() let submissionModel = realm.objects(SubmissionModel.self).filter({ $0.id == submissionId }).first! let entryModels = submissionModel.entryModels // 检查所有必填、为空且未隐藏的条目详情字段 let emptyEntryModels = entryModels.filter({ $0.entryDetailArray.filter({ $0.entryDetailValue.isEmpty && $0.isMandatory && !($0.isHidden) }).count > 0 }) return Array(emptyEntryModels) }
错误就出在这行嵌套filter的代码上:
let emptyEntryModels = entryModels.filter({ $0.entryDetailArray.filter({ $0.entryDetailValue.isEmpty && $0.isMandatory && !($0.isHidden) }).count > 0 })
问题原因
Swift 4.2对Sequence和Collection协议的filter方法做了细节调整,当嵌套调用filter时,编译器有时候无法准确推断闭包参数的类型,尤其是当内外层操作的集合元素类型上下文不够明确的时候,就会抛出这种歧义错误。
解决方案
这里有两种可行的修复方式,还顺便优化了代码的性能和安全性:
方案1:用contains替代内层filter+count>0(推荐)
你的内层逻辑其实是判断entryDetailArray里是否存在符合条件的元素,用contains比filter.count > 0更高效(contains找到第一个匹配项就停止遍历),同时也能消除编译器的歧义:
func validateSubmission(_ submissionId: Int) -> [EntryModel] { let realm = try! Realm() // 替换强制解包为guard let,避免崩溃风险 guard let submissionModel = realm.objects(SubmissionModel.self).filter({ $0.id == submissionId }).first else { return [] } let entryModels = submissionModel.entryModels let emptyEntryModels = entryModels.filter { entry in // 用contains直接判断是否存在符合条件的详情项 return entry.entryDetailArray.contains { detail in detail.entryDetailValue.isEmpty && detail.isMandatory && !detail.isHidden } } return Array(emptyEntryModels) }
方案2:明确指定闭包参数类型
如果一定要保留filter的嵌套写法,可以通过给闭包参数显式指定类型,帮助编译器明确推断:
func validateSubmission(_ submissionId: Int) -> [EntryModel] { let realm = try! Realm() let submissionModel = realm.objects(SubmissionModel.self).filter({ $0.id == submissionId }).first! let entryModels = submissionModel.entryModels let emptyEntryModels = entryModels.filter({ (entry: EntryModel) in entry.entryDetailArray.filter({ (detail: EntryDetailModel) in detail.entryDetailValue.isEmpty && detail.isMandatory && !detail.isHidden }).count > 0 }) return Array(emptyEntryModels) }
额外建议
代码里的try! Realm()和first!都是强制解包,在运行时如果Realm初始化失败或者找不到对应submissionId的数据,会直接导致崩溃,建议替换为可选绑定或者错误处理逻辑,比如方案1里的guard let写法。
内容的提问来源于stack exchange,提问作者Lastmboy
相关产品推荐
相关产品推荐

