如果我们想给一个struct
或者class
拓展功能,最直白的方式就是修改它们的代码,把我们想追加的函数代码写进去即可。但在一些情况下,我们没有这样做的机会,最典型的场景就是我们在使用别人提供的类库,源代码不是我们写的已经被别人封装过了,自然我们也没有机会修改别人的代码来实现我们想要的功能了。
这个时候,就该我们今天的主角Extension
出场了。有了Extension
我们就可以对已经存在的struct
或者class
拓展功能了。比如,我们想判断一个整数是不是奇数,通常简单的做法是这样:
func isOdd(num:Int) -> Bool{
return num%2 != 0
}
print(isOdd(num: 4))
print(isOdd(num: 5))
但是如果有了Extension
,我们就可以把isOdd
函数直接写到Int
里了,至少用起来是这样的。
extension Int {
func isOdd() -> Bool{
return self%2 != 0
}
}
print(4.isOdd())
print(5.isOdd())
明显上面的写法在最终调用时更加符合直觉,也更优雅。
考虑到extension
中也可以扩展计算属性(Computed Properties)
,我们还可以再进一步:
extension Int {
var isOdd:Bool {
return self%2 != 0
}
}
print(4.isOdd)
print(5.isOdd)
extension
不光可以扩展普通的函数,也可以扩展构造函数。比如下面这个例子:
import Foundation
extension Date{
init (_ str:String){
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let target = dateFormatter.date(from: String(str))!
self.init(timeIntervalSince1970: target.timeIntervalSince1970)
}
}
var aDate = Date("2022-06-01")
print(aDate)
在上面的例子中,我们给Date
增加了一个新的构造函数,可以传入形如yyyy-MM-dd
的字符串构建一个Date
。
除了普通函数、计算属性以及构造函数。还有一种能够扮演逻辑功能的特殊语法我们之前还没有讲过,就是Subscripts(下标)
。我们最常遇到的场景就是数组,你应该已经接触过了,比如这样:
var nums = [1,2,3,4,5]
print(nums[0])
除了数组之外,即使是struct
或者class
,只要源码在自己手上,都可以很容易的通过添加subscript
获得对下标的支持,以达到类似于数组的使用效果。但是当源码不掌握在自己手里的时候,我们就可以借助extension
对现有的struct
及class
进行改造了。比如下面这段代码:
var str:String = "abc"
print(str[0])
我们期望程序返回a
,但事实上程序会报错。这时我们就可以通过extension
自己实现对String
功能的增强了:
extension String {
subscript(digitIndex: Int) -> String {
if digitIndex < 0 || digitIndex >= self.count{
return ""
}
let arr = self.map{String($0)}
return arr[digitIndex]
}
}
print("abc"[0])
有了上面的代码,我们就可以把String
当成Array
一样,优雅地通过下标的方式获取到对应位置的单个字符串了。如果我们传入的下标不在支持的范围内,那程序就返回一个""
(空字符串)。
extension
可以跟我们上次讲的protocol
结合在一起使用,比如这样:
protocol Hello {
func say()
}
extension Int:Hello{
func say() {
print("Hello, \(self)")
}
}
4.say()
有了这样的特性,我们就可以让别人写的struct
或者class
遵照我们定义的protocol
行事了。
最后再说一下,extension
除了可以拓展功能外,可以拓展静态属性,一个常见的场景是在使用SwiftUI
时,需要对一些公共的颜色进行预知,方便之后的使用。那么就可以这样:
import SwiftUI
extension Color {
static var background = Color("background")
static var separator = Color("separator")
static var textColor = Color("text_color")
}
这样我们在编写UI
代码时就可以优雅地访问颜色了:
var body: some View {
VStack{
Text("hello")
.foregroundColor(.textColor)
Color.separator.frame(width:100, height:2)
}
.background(.background)
}
参考资料:
- https://docs.swift.org/swift-book/LanguageGuide/Extensions.html
- https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html