[Swift]扩展
1. Swift扩展的概念以及重要性: 1) 扩展的概念:是指向一个已有的类、结构体、枚举添加新的功能(属性、方法、下标等),但不需要修改这些类型的源代码甚至不需要拥有这些类型的源代码; 2) 和继承的区别:首先扩展可以运用到不止类(还包括结构体和下标,甚至是Int、Double等基本类型,实际上这些基本类型也是用结构体来实现的);其次,虽然可以通过继承在新的子类中添加更多
1. Swift扩展的概念以及重要性:
1) 扩展的概念:是指向一个已有的类、结构体、枚举添加新的功能(属性、方法、下标等),但不需要修改这些类型的源代码甚至不需要拥有这些类型的源代码;
2) 和继承的区别:首先扩展可以运用到不止类(还包括结构体和下标,甚至是Int、Double等基本类型,实际上这些基本类型也是用结构体来实现的);
其次,虽然可以通过继承在新的子类中添加更多的功能,但是继承机制比较复杂而有时作者会限制类的继承(比如使用final声明等),但是扩展不受这些约束(比如一个类被声明为final的,虽然其不可被继承,但是仍然可以对其进行扩展):
final class A {
}
extension A { // OK! 虽然不能继承但是仍能扩展
func f() {
println("haha")
}
}
这里提一下扩展的语法:
extension 类名 {
扩展的内容...
}
3) 扩展的作用:
i) 特别是在没有权限获取源代码的情况下也可以扩展类型,提高了逆向建模的能力;
ii) 可以说扩展是一种轻量级的继承;
iii) 在任何时候都要优先考虑使用扩展(一般Java程序员都会保守地选择继承),这是从简的编程原则,只有当扩展无法满足需求的时候再考略使用继承;
iv) 扩展在Swift中地位非常重要,很多Swift API以及一些Swift的基本类型都是通过扩展实现的,比如String的很多方法就是通过扩展实现的;
4) 可以对基本类型进行扩展,比如Int、String、Double、Character等,因为这些基本类型底层都是用结构体包装的!
5) Swift允许扩展的内容:
i) 对于值类型(结构体和枚举)可以扩展静态存储属性,但是对于类类型则不能扩展静态存储属性;
ii) 对于任何类型都不能扩展实例存储属性;
iii) 可以扩展计算属性(实例、静态都行);
iv) 可以扩展方法(实例、静态都行);
v) 可以扩展构造器;
vi) 可以扩展下标;
vii) 可以扩展嵌套类;
viii) 可以扩展使其适配一个或多个协议;
6) 扩展的最大亮点:在定义扩展后全局有效,即那些在扩展前定义的对象也可以使用扩展出的新功能;
2. 扩展静态存储属性:
1) 只对于值类型成立;
2) 举例:
extension Int {
static var sta_var = 90 // OK! Int是值类型的结构体
}
class A {
}
//extension A {
// static var test = 11 // Bad! 不能扩展类类型的静态存储属性
//}
struct B {
}
extension B {
static var test = 11 // OK! 结构体类型可以
}
enum C {
}
extension C {
static var test = 22 // OK! 枚举类型也是值类型,同样也可以扩展静态存储属性
}
3) 但是对于任何类型都不能扩展实例存储属性!
3. 扩展计算属性:!注意值类型和枚举类型之间的区别
extension Int {
var errMessage: String { // 扩展实例的只读计算属性
switch self {
case -7: return "没有数据"
case -6: return "日期格式有误"
case -5: return "内容格式有误"
case -4: return "ID为空"
case -3: return "数据访问失败"
case -2: return "空间不足"
case -1: return "用户不存在"
default: return ""
}
}
}
println((-3).errMessage) // 数据访问失败,注意使用括号否则编译解析会有问题
struct A {
}
extension A {
static var x = 10 // 扩展静态存储属性
var y: Int { // 扩展实例可读可写计算属性对静态存储属性进行维护
get {
return A.x
}
set {
A.x = newValue
}
}
}
println(A.x) // 10
var a = A()
println(a.y) // 10
a.y = 30
println(A.x) // 30
extension Double { // 模拟单位表示法
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
}
var some_km = 5.0.km
var some_m = 3.9.m
var some_cm = 90.3.cm
var some_mm = 33.23.mm
println(some_km) // 5000.0
println(some_m) // 3.9
println(some_cm) // 0.903
println(some_mm) // 0.03323
class B {
}
extension B {
class var test: Int { // 扩展静态计算属性
return 23
}
}
4. 扩展构造器:
对于结构体可以扩展普通构造器和代理构造器,但是对于类只能扩展便利构造器但不能扩展指定构造器!
struct A {
var a = 15
var b = 20
init(a: Int, b: Int) {
self.a = a
self.b = b
}
}
extension A { // 对于结构体既可以扩展普通构造器也可以扩展代理构造器
init(a: Int) {
self.a = a
}
init() {
self.init(a: 23, b: 88)
}
}
extension A { // 可以连续扩展任意多次
init(s: String) {
self.init()
}
}
class B {
var a: Int
var b: Int
init(a: Int, b: Int) {
self.a = a
self.b = b
}
}
extension B { // 对于类只能扩展便利构造器不能扩展指定构造器,否则会报错!
// !由于类只能扩展便利构造器而不能扩展指定构造器,因此就不能用super调用父类构造器了!
convenience init() {
self.init(a: 10, b: 20)
}
}
5. 扩展方法:
按照之前讲过的定义方法的规则可以随意扩展:
extension Double {
static let rate = 3.773 // 结构体可以扩展静态存储结构
func getTotal() -> Double { // 扩展实例方法
return Double.rate * self
}
static func computeTotal(amount: Double) -> Double { // 扩展静态方法
return rate * amount
}
mutating func doubleIt() { // 要改变结构体本身的内容需要变异!
self = self * 2
}
}
class A { // 注意!类只支持静态计算属性不支持静态存储属性
var value: Double = 234.32
}
// 相应的类类型的版本
extension A {
class var rate: Double {
return 3.231
}
func getTotal() -> Double {
return value * A.rate
}
class func computeTotal(amount: Double) -> Double {
return rate * amount
}
func doubleIt() {
value = value * 2
}
}
一个扩展方法的非常有趣的例子:为Int扩展一个方法,使用Int的数值n重复n次动作,这个动作作为闭包作为参数传入扩展的方法
extension Int {
func rep(task: () -> ()) {
for _ in 0..<self {
task()
}
}
}
3.rep { println("haha") }
就跟普通定义下标一样,这里介绍两个扩展String和Int下标的有趣的例子:
扩展String下标,用来模仿C语言字符数组随机访问的功能
extension String {
subscript(index: Int) -> String { // 返回的字符用String包装
if index < 0 || index + 1 > countElements(self) {
return ""
}
var i = 0
for char in self { // 从字符串中取出的元素是Character类型的
if i == index {
return String(char) // 需要包装成String类型
}
i++
}
return ""
}
}
println("abc"[2]) // c
扩展Int下标,获得从低到高的第n位数字,第0位是最低位:
extension Int {
subscript(index: Int) -> Int {
var base = 1
for _ in 0..<index {
base *= 10
}
return (self / base) % 10
}
}
println(23423[2]) // 4
6. 扩展嵌套类型:
就和定义普通的嵌套类型一样,这里介绍一下在Character中扩展一个枚举类型,用于对字符的类型进行分类(元音、辅音等):
extension Character {
enum Kind: String {
case Vowel = "Vowel"
case Consonant = "Consonant"
case Other = "Other"
}
var kind: Kind {
switch String(self).lowercaseString {
case "a", "e", "i", "o", "u": return .Vowel
case "b", "c", "d", "f", "g": return .Consonant
default: return .Other
}
}
}
println(Character("I").kind.rawValue) // Vowel
7. 扩展适配协议:
可以扩展一个类型使其匹配一个或多个协议,这里只介绍其语法:
extension Type: Protocol1, Protocol2... {
...
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)