Swift Tips 012 - Calling initializers with dot syntax and passing them as closures
每天了解一点不一样的 Swift 小知识
代码截图
小笔记
这段代码在说什么
今天的代码截图提到了 Swift 构造器的另一种使用方法,即用点语法(dot syntax)获取实例或者获取构造方法本身。
在获取实例上,使用点语法与我们常用的实例生成方式没有区别,例如下面的代码,a
和 b
都是 Fahrenheit
的一个实例,没有什么区别。
let a = Date()
let b = Date.init()
而在获取构造方法上,使用点语法其实就是获取了一个与构造方法相同入参和返回值的闭包,例如下面代码中的 a
和 Date.init
表示的是一回事。
let a = { () -> Date in
return Date()
}
为什么能使用点语法调用 init 方法
Swift 里点语法这个语法糖能够帮助开发者直接调用某个类型或者类型实例下的方法和属性。
对于 init 方法而言,它虽然不是用 func
方式定义的,但它本质还是类型里的一个类方法。
所以用点语法直接调用 init 方法是没有任何问题的,只是我们通常会使用 Date()
的方式来创建实例。
这样做的好处
在代码截图里的场景下,如果不使用构造函数作为函数默认值的话,我们可能会将代码写成下面的形式:
class AnotherLogger {
private let storage: LogStorage
private let dateProvider: () -> Date
init(storage: LogStorage = LogStorage(), dateProvider: @escaping () -> Date = {Date()}) {
self.storage = storage
self.dateProvider = dateProvider
}
func log(event: Event) {
storage.store(event: event, date: dateProvider())
}
}
与代码截图里的写法对比,我们使用了 {Date()}
闭包作为默认参数,或许你觉得这么写也还行,但在实际开发过程中,这种用闭包做参数的写法并不一定是种优雅的写法,这里举一个例子:
// A: .init 的写法
class AnotherLogger {
private let storage: LogStorage
private let dateProvider: (TimeInterval, Date) -> Date
init(storage: LogStorage = LogStorage(), dateProvider: @escaping (TimeInterval, Date) -> Date = Date.init) {
self.storage = storage
self.dateProvider = dateProvider
}
}
// B:闭包的写法
class AnotherLogger {
private let storage: LogStorage
private let dateProvider: (TimeInterval, Date) -> Date
init(storage: LogStorage = LogStorage(), dateProvider: @escaping (TimeInterval, Date) -> Date = {(time: TimeInterval, date: Date) in
return Date.init(timeInterval: time, since: date)
})
{
self.storage = storage
self.dateProvider = dateProvider
}
}
这么一看,是不是 .init
的语法还不错!