来源

 

Swift 中的扩展可以:
  1. 计算型属性和计算静态属性
  2. 实例方法和静态方法
  3. 构造器
  4. 定义脚本
  5. 定义和使用新的嵌套类型

 

注意:如果你定义了一个扩展向一个已有类型添加新功能,那么这个新功能对该类型的所有已有实例中都是可用的,即使它们是在你的这个扩展的前面定义的也一样。

 

扩展语法

声明一个扩展使用关键字extension:

extension SomeType { 
    // 加到SomeType的新功能写到这里 
} 
一个扩展可以扩展一个已有类型,使其能够适配一个或多个协议(protocol)。当这种情况发生时,接口的名字应该完全按照类或结构体的名字的方式进行书写:
extension SomeType: SomeProtocol, AnotherProctocol { 
    // 协议实现写到这里 
} 
按照这种方式添加的协议遵循者(protocol conformance)被称之为在扩展中添加协议遵循者

 

计算型属性

扩展可以向已有类型添加计算型实例属性和计算型类型属性。下面的例子向 Swift 的内建Double类型添加了5个计算型实例属性,从而提供与距离单位协作的基本支持。

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 ft: Double { return self / 3.28084 } 
} 
let oneInch = 25.4.mm 
println("One inch is \(oneInch) meters") 
// 打印输出:"One inch is 0.0254 meters" 
let threeFeet = 3.ft 
println("Three feet is \(threeFeet) meters") 
// 打印输出:"Three feet is 0.914399970739201 meters" 

这些属性是只读的计算型属性,从简考虑它们不用get关键字表示。它们的返回值是Double型,而且可以用于所有接受Double的数学计算中:

let aMarathon = 42.km + 195.m 
println("A marathon is \(aMarathon) meters long") 
// 打印输出:"A marathon is 42495.0 meters long" 

 

注意:扩展可以添加新的计算属性,但是不可以添加存储属性,也不可以向已有属性添加属性观察者(property observers)。

 

构造器(Initializers)

下面的例子定义了一个用于描述几何矩形的定制结构体Rect。这个例子同时定义了两个辅助结构体Size和Point,它们都把0.0作为所有属性的默认值:

struct Size { 
    var width = 0.0, height = 0.0 
} 
struct Point { 
    var x = 0.0, y = 0.0 
} 
struct Rect { 
    var origin = Point() 
    var size = Size() 
} 
let defaultRect = Rect() 
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), 
    size: Size(width: 5.0, height: 5.0)) 
extension Rect { // 扩展Rect
    init(center: Point, size: Size) { 
        let originX = center.x - (size.width / 2) 
        let originY = center.y - (size.height / 2) 
        self.init(origin: Point(x: originX, y: originY), size: size) 
    } 
} 

这个新的构造器首先根据提供的center和size值计算一个合适的原点。然后调用该结构体自动的成员构造器init(origin:size:),该构造器将新的原点和大小存到了合适的属性中:

let centerRect = Rect(center: Point(x: 4.0, y: 4.0), 
    size: Size(width: 3.0, height: 3.0)) 
// centerRect的原点是 (2.5, 2.5),大小是 (3.0, 3.0) 

 

注意:如果你使用扩展提供了一个新的构造器,你必须保证构造过程能够让所有实例完全初始化。

 

方法(Methods)

extension Int { // 扩展Int
  // 扩展了接收一个()->()参数的函数,没有返回值的函数
  func repetitions(task: () -> ()) {
    for i in 0..self {
      task()
    }
  }
}
// 使用
3.repetitions({ 
    println("Hello!") 
    }) 
// Hello! 
// Hello! 
// Hello! 
// 使用闭包调用更加简洁
3.repetitions{ 
    println("Goodbye!") 
} 
// Goodbye! 
// Goodbye! 
// Goodbye! 

 

扩展变化方法

通过扩展添加的实例方法也可以修改该实例本身。结构体和枚举类型中修改self或其属性的方法必须将该实例方法标注为mutating

extension Int { 
    mutating func square() {  // 变异方法
        self = self * self 
    } 
} 
var someInt = 3 
someInt.square() 
// someInt 现在值是 9 

 

脚本(Subscripts)

extension Int { 
    subscript(digitIndex: Int) -> Int {  // 扩展脚本
        var decimalBase = 1 
            for _ in 1...digitIndex { 
                decimalBase *= 10 
            } 
        return (self / decimalBase) % 10 
    } 
} 
746381295[0] 
// returns 5 
746381295[1] 
// returns 9 
746381295[2] 
// returns 2 
746381295[8] 
// returns 7 

如果该Int值没有足够的位数,即下标越界,那么上述实现的下标会返回0:

746381295[9] 
//returns 0, 

 

嵌套类型(Nested Types)

扩展可以向已有的类、结构体和枚举添加新的嵌套类型:

extension Character { 
    enum Kind { 
        case Vowel, Consonant, Other 
    } 
    var kind: Kind { 
        switch String(self).lowercaseString { 
        case "a", "e", "i", "o", "u": 
            return .Vowel 
        case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", 
             "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": 
            return .Consonant 
        default: 
            return .Other 
        } 
    } 
} 

现在,这个嵌套枚举可以和一个Character值联合使用了:

func printLetterKinds(word: String) { 
    println("'\\(word)' is made up of the following kinds of letters:") 
    for character in word { 
        switch character.kind { 
        case .Vowel: 
            print("vowel ") 
        case .Consonant: 
            print("consonant ") 
        case .Other: 
            print("other ") 
        } 
    } 
    print("\n") 
} 
printLetterKinds("Hello") 
// 'Hello' is made up of the following kinds of letters: 
// consonant vowel consonant consonant vowel 

 

注意:由于已知character.kind是Character.Kind型,所以Character.Kind中的所有成员值都可以使用switch语句里的形式简写,比如使用 .Vowel代替Character.Kind.Vowel

 

2015-03-24

20:13:18

posted on 2015-03-25 20:13  道无涯  阅读(105)  评论(0编辑  收藏  举报