如何在Predicate宏外部复用谓词逻辑?
如何在Predicate宏外部复用谓词逻辑?
嘿,我完全懂你的困扰——你现在用#Predicate宏构建复合谓词时,那些日期判断的逻辑挺复杂的,想把核心逻辑抽出来复用,不想在多个地方重复写相同的代码对吧?其实有个很简单的方案能解决这个问题:把核心的判断逻辑单独抽成一个纯函数,不管是在#Predicate宏内部,还是生成Predicate的工具函数里,都直接调用这个函数就行。
我结合你的代码给你改改,一看就明白:
首先,把日期范围判断的核心逻辑,抽成Item的静态方法(普通函数也可以,看你习惯):
extension Item { static func isInDateRange(_ item: Item, range: ClosedRange<Date>) -> Bool { let distantFuture = Date.distantFuture // 计算实际生效的起止日期 let effectiveStart = item.startDate ?? item.endDate ?? distantFuture let effectiveEnd = item.endDate ?? item.startDate! return effectiveStart < range.upperBound && effectiveEnd >= range.lowerBound } }
接下来,你原来的startEndAppliesDuring函数就能大幅简化,不用再重复写那些日期判断代码了:
static func startEndAppliesDuring(_ range: ClosedRange<Date>) -> Predicate<Item> { #Predicate<Item> { item in Item.isInDateRange(item, range: range) } }
甚至在View里的复合谓词宏里,也能直接复用这个逻辑,不用提前生成startEndShowsOnDay这个Predicate(当然如果有需要保留也完全没问题):
let predicate = #Predicate<Item> { item in createdOnDay.evaluate(item) || (isStartEnd.evaluate(item) && Item.isInDateRange(item, range: dayRange)) }
为啥这个方法可行?因为#Predicate宏支持在闭包内调用纯Swift函数——只要你的函数是无副作用的(输入相同输出就相同),宏就能自动把函数调用转换成对应的谓词表达式,完全不影响Predicate的功能。
这么做的好处也很实在:
- 彻底消除代码重复,所有需要判断日期范围的地方都共用同一套逻辑
- 维护成本极低,以后要调整日期判断规则,只需要改这一个函数,所有用到的地方都会同步更新
- 代码可读性大幅提升,别人一看
isInDateRange就知道是在做什么,不用去啃一堆复杂的条件组合
备注:内容来源于stack exchange,提问作者Giles
相关产品推荐
相关产品推荐

