我一直试图在Swift中做一些我认为应该相对简单的事情 - 将一个闭包存储在一个结构中的属性中,这样它就可以用于通过使用该结构的另一个属性来过滤数组。但是我遇到了一个块 - 我不能在struct initialiser中添加闭包,因为它想要引用的变量不存在,我不能把它变成一个惰性变量。它是协议的一部分(不确定这是否会起作用),并且在结构初始化之后我无法分配它,因为它将捕获eI进行赋值的对象的上下文并尝试使用对于当地的财产。简化的方案如下:
struct EventSpec {
var dateRange: DateInterval
var filterClosure: ((Date) -> Bool)?
init( dateRange: DateInterval) {
self.dateRange = dateRange
}
func provideMatchingEvents(for events: [Event] {
return events.filters{filterClosure($0.date)}
}
struct Event {
name: String
date: Date
}
理想情况下想要初始化
eventSpec = EventSpec(dateRange: aDateRamge, filterClosure: { date in self.dateRange.contains(date)}
但这并不起作用,因为此时没有self.dateRange。
尝试之后直接或通过“建造者”添加封口。功能不起作用,因为它捕获了自我'它涉及的地方,而不是访问EventSpec的dateRange属性。
我确定这应该是一种常见的模式,而我'遗漏了一些明显的东西,但只能找到引用(很多)将闭包添加为不引用其他属性的变量。
(我意识到如果我在结构中对闭包进行了硬编码,我可以通过标准捕获列表访问局部变量,但这样就无法在运行时定义过滤器。)
任何想法?
答案 0 :(得分:1)
闭包内部代码的范围在于它所写入的对象中。不是它传入的对象。
所以...
EventSpec(dateRange: aDateRamge) { date in
self.dateRange.contains(date)
}
self
是创建EventSpec
对象的地方。
您可以做的是捕获闭包中的dateRange
。
所以你可以像你这样重新定义EventSpec ......
struct EventSpec {
var filterClosure: ((Date) -> Bool)?
func provideMatchingEvents(for events: [Event]) {
return events.filters{ filterClosure($0.date) }
}
}
然后创建它... ...
let dateRange = //some date range that you have already got
let eventSpec = EventSpec(filterClosure: { dateRange.contains($0) })
// in this line the dateRange is captured by the closure so you don't need to capture it as a separate property
这会做你想做的事情。