Swift基础语法(十二)扩展
扩展的核心在于扩展的内容不能改变原有实例的内存结构、不能修改原有功能,本文对常见的计算属性、下标、协议、初始化器、声明、协议实现、泛型的扩展进行了示例分析
主要内容:
- 扩展认识
- 扩展示例
扩展
扩展可以为枚举、结构体、类、协议增加新功能,并且不能更改原有功能以及实例内存,有点类似于OC中的分类
扩展不可以进行的操作:
- 不能覆盖原有功能方法
- 不能增加存储属性
- 不能向已有的属性添加属性观察器
- 不能添加父类
- 不能添加指定初始化器,不能添加反初始化器
增加计算属性
代码:
//1、增加计算属性
extension Double {
var km: Double { self * 1_000.0 }
var m: Double { self }
var dm: Double { self / 10.0 }
var cm: Double { self / 100.0 }
var mm: Double { self / 1_000.0 }
}
var d = 10.0
print(d.km)
print(d.m)
print(d.dm)
print(d.cm)
print(d.mm)
增加下标
代码:
//2、增加下标
extension Array {
subscript(nullable idx: Int) -> Element? {
if (startIndex..<endIndex).contains(idx) {
return self [idx]
}
return nil
}
}
var arr: Array<Int> = [20,10,30]
print(arr[nullable: 3] as Any)
说明:
1、原有类的泛型在扩展中依然可以使用
2、这里的扩展是用给数组增加越界判断
3、注意这里的范围是..<,也就是不包含最后一个值,这是因为endIndex并不是指向最后一个值的索引,而是最后一个值的下一位索引
4、比如这里的endIndex其实是3,而不是2
5、如果数组为空,那么就是0..<0,此时在语义上解释既包括0也不包括0,其实是不包括0
6、因为返回的是可选项,所以使用as Any
增加协议
代码:
//3、增加协议
class Person {
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
}
extension Person : Equatable {
//扩展一个方法
static func == (left: Person, right: Person) -> Bool {
left.age == right.age && left.name == right.name
}
//只能扩展便捷初始化器
convenience init() {
self.init(age: 0, name: "")
}
}
let p1 = Person.init(age: 10, name: "WY")
let p2 = Person.init(age: 20, name: "WY")
print(p1 == p2)//false
说明:
- 可以给类型扩展一个协议
- 另外类中扩展init只能扩展便捷初始化器
增加初始化器
代码:
//4、增加初始化器
struct Point {
var x: Int = 0
var y: Int = 0
}
extension Point {
init(_ point: Point) {
self.init(x: point.x, y: point.y)
}
}
//扩展初始化器后,并不会覆盖之前的初始化器,没有覆盖,而只是扩展
var p41 = Point()
var p42 = Point(x: 10)
var p43 = Point(y: 20)
var p44 = Point(x: 10, y: 20)
var p45 = Point(p44)
说明:
1、给结构体扩展了一个初始化器,结构体可以直接扩展一个初始化器,因为它是不区分便捷的还是指定初始化器
2、注意此时不会覆盖以前的四个初始化器,这也容易理解,在Swift中扩展是不能更改原有类型中的功能和内存结构的
必需初始化器不能添加扩展中
说明:
1、我们知道一个类遵守协议时,并且实现这个协议的init方法,需要使用required,因为需要子类也实现这个init
2、但是这个初始化器只能加载类中,而不能加在类的扩展中,也容易理解,这个扩展是新增功能,但是required init()是必需存在的,必需存在的东西自然要放在类本身中
3、因此这个与是否遵守协议无关,只要是required,那么就必须放在类本身中
增加已遵守协议实现的协议声明
如果一个类型已经实现了协议的所有要求,但是没有声明遵守这个协议,那么可以通过扩展来让他遵守
代码:
//5、增加协议声明
protocol TestProtocol {
func test()
}
class TestClass {
func test() {
print("test")
}
}
extension TestClass : TestProtocol {}
TestClass().test()
判断奇数的案例
/*
判断奇数案例
两种方案:
1. 创建isOdd函数,传入遵守BinaryInteger协议的类型,进行比较
2. 扩展BinaryInteger协议,增加isOdd方法
*/
func isOdd<T: BinaryInteger>(_ i: T) -> Bool {
i % 2 != 0
}
extension BinaryInteger {
func isOdd() -> Bool { self % 2 != 0 }
}
print(10.isOdd())//false
print((-3).isOdd())//true
说明:
1、此处给协议可扩展了一个功能,用来判断奇数
2、在使用泛型时,又需要指明遵守某个协议,防止其他乱七八糟的类型也进来判断
3、BinaryInteger协议是所有整数类型遵守的协议,因此这里放上它
增加协议实现
代码:
//6、增加协议实现
protocol TestProtocol6 {
func test1()
}
//增加协议方法实现,增加协议方法
extension TestProtocol6 {
func test1() {
print("TestProtocol test1")
}
func test2() {
print("TestProtocol test2")
}
}
//类中自己再实现一下方法
class TestClass6 : TestProtocol6 {
func test1() { print("TestClass test1") }
func test2() { print("TestClass test2") }
}
var cls = TestClass6()
cls.test1() // TestClass test1
cls.test2() // TestClass test2 隐式遵守协议,会打印类的实现
var cls2: TestProtocol6 = TestClass6()
cls2.test1() // TestClass test1
cls2.test2() // TestProtocol test2 显式遵守协议,会打印默认的实现
说明:
1、扩展协议可以给协议中定义的方法供实现,这就是默认实现
2、遵守该协议的类如果不去实现也不会报错,因为已经有了默认实现
3、扩展协议还可以增加功能
4、注意此时的打印,如果cls显式或隐式的显示遵守了TestProtocol协议,会有不同的打印结果
增加泛型
代码:
//7、增加泛型
//下是一个模拟栈的类
class Stack<E> {
var elements = [E]()
func push(_ element: E) {
elements.append(element)
}
func pop() -> E { elements.removeLast() }
func size() -> Int { elements.count }
}
// 1、扩展中依然可以使用原类型中的泛型类型
extension Stack {
func top() -> E { elements.last! }
}
// 2、符合条件才扩展(给Stack增加泛型,并添加泛型约束
extension Stack : Equatable where E : Equatable {
static func == (left: Stack, right: Stack) -> Bool {
left.elements == right.elements
}
}
说明:
1、扩展可以使用原类型的泛型
2、扩展可以增加泛型