我一直在尝试在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属性。
我确定这应该是一个常见的模式,我错过了一些明显的东西,但只能找到引用(很多)将闭包添加为不引用其他属性的变量。
(我意识到如果我在结构中对闭包进行了硬编码,我可以通过标准捕获列表访问局部变量,但是这样就无法在运行时定义过滤器)。
任何想法?
闭包内部的代码范围是在它写入的对象中。不是它传入的对象。
所以......
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
这会做你想做的事情。