Posts 擴展(Extensions)翻譯與筆記
Post
Cancel

擴展(Extensions)翻譯與筆記

本文根據 The swift programming language ,進行翻譯以及筆記整理。

Swift 中的 extensions 可以:

  • 添加 計算型 instance properties 和計算型 type properties
  • 定義 instance 方法和 type 方法
  • 提供新的 initializers
  • 定義下標(subscripts)
  • 定義和使用新的 nested types
  • 使一個已存在的的類型符合某個協議

Extension 的語法

宣告方式:

1
2
3
extension SomeType {
    // new functionality to add to SomeType goes here
}

對想要擴展的 type 可以使其採用一種或多種 protocols

1
2
3
extension SomeType: SomeProtocol, AnotherProtocol {
    // implementation of protocol requirements goes here
}

Computed Properties (計算屬性)

Extension 可以將計算的實例屬性和計算的類型屬性添加到現有類型。下面例子向 Swift 的內置 Double 類型添加了五個計算實例屬性,為使用距離單位提供基本支持:

1
2
3
4
5
6
7
8
9
10
11
12
13
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
print("One inch is \(oneInch) meters")
// Prints "One inch is 0.0254 meters"
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters")
// Prints "Three feet is 0.914399970739201 meters"

這些計算的屬性表示Double值應視為某個長度單位。儘管將它們實現為計算屬性,但是可以使用點語法將這些屬性的名稱附加到浮點文字值上,以作為使用該文字來執行距離轉換的一種方式。

這些屬性是 read-only 的計算屬性,因此為了簡潔起見,它們不使用get關鍵字表示。它們的返回值是Double類型的,並且可以在接受Double的任何地方的數學計算中使用:

1
2
3
let aMarathon = 42.km + 195.m
print("A marathon is \(aMarathon) meters long")
// Prints "A marathon is 42195.0 meters long"

Initializers (初始化器)

擴展可以向現有的類型添加新的初始化器。這樣一來就可以擴展其他類型,以接受自己自定義的類型作為初始化程序參數,或者提供未包含在該類型的原始實現中的其他初始化選項。

下面例子定義了一個自定義的Rect結構來表示一個幾何矩形。該示例還定義了兩個支持的結構,稱為“Size”和“Point”,這兩個結構的所有屬性的默認值都是0.0:

1
2
3
4
5
6
7
8
9
10
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()
}

因為Rect結構為其所有屬性提供默認值,所以它會自動接收默認初始化程序和成員初始化程序,如默認初始化程序中所述。這些初始化程序可用於創建新的Rect實例:

1
2
3
4
5
let defaultRect = Rect()
let memberwiseRect = Rect(
    origin: Point(x: 2.0, y: 2.0), 
    size: Size(width: 5.0, height: 5.0)
)

您可以擴展Rect結構以提供採用特定中心點和大小的附加初始化程序:

1
2
3
4
5
6
7
extension 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)
    }
}

這個新的 initializer 開始於根據提供的 centersize 計算適當的原點。然後,初始化程序會調用結構的 automatic memberwise initializer init(origin:size :),它將新的 originsize 存儲在適當的屬性中:

1
2
3
4
5
let centerRect = Rect(
    center: Point(x: 4.0, y: 4.0), 
    size: Size(width: 3.0, height: 3.0)
)
// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)

Methods (方法相關)

Extensions 可以向現有類型添加新的實例方法和類型方法。下面例子向 Int 類型添加一個稱為 repetitions 的新實例方法:

1
2
3
4
5
6
7
extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }
}

repetitions(task :) 方法採用 ()-> Void 類型的單個 argument,這個 function 是沒有參數且不返回值的函數。

定義此 extension 後,可以在任何整數上調用 repetitions(task :) method 來執行多次任務:

1
2
3
4
5
6
3.repetitions {
    print("Hello!")
}
// Hello!
// Hello!
// Hello!

特化的 instance 方法

可以以 extension 的方式來修改 instance 本身。 當 Structure and enumeration methods 要修改時,需將 instance 標註為 mutating

下面這個例子,對 Swift’s Int 的值做平方的運算。

1
2
3
4
5
6
7
8
extension Int {
    mutating func square() {
        self = self * self
    }
}
var someInt = 3
someInt.square()
// someInt is now 9

Subscripts (下標)

Extensions 可以對已存在的類型新增新的 subscripts。 下面這個例子是幫 Swift’s built-in Int type 新增一個 subscript。 這個 subscript [n] 會回傳十進制中由右數起的第 n 位數值:

1
2
123456789[0] returns 9
123456789[1] returns 8

…and so on:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
extension Int {
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        for _ in 0..<digitIndex {
            decimalBase *= 10
        }
        return (self / decimalBase) % 10
    }
}
746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7

如果輸入的數值超出擁有的位數,則會回傳 0 ,可視為在其位數前補 0。

1
2
3
746381295[9]
// returns 0, as if you had requested:
0746381295[9]

Nested Types (巢狀)

Extensions 可以幫已存在的 classes, structures, and enumerations 加入新的 nested types:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
extension Int {
    enum Kind {
        case negative, zero, positive
    }
    var kind: Kind {
        switch self {
        case 0:
            return .zero
        case let x where x > 0:
            return .positive
        default:
            return .negative
        }
    }
}

這個例子為 Int 新增了一個叫做 Kind 的 nested enumeration,用來表示數字的類型具體來說,它表示數字是負數,零數還是正數。

並寫在例子中也新增了一個名為 kind 的 computed instance property,他會為整數回傳適當的 Kind enumeration。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func printIntegerKinds(_ numbers: [Int]) {
    for number in numbers {
        switch number.kind {
        case .negative:
            print("- ", terminator: "")
        case .zero:
            print("0 ", terminator: "")
        case .positive:
            print("+ ", terminator: "")
        }
    }
    print("")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
// Prints "+ + - 0 - 0 + "
This post is licensed under CC BY 4.0 by the author.

Activity 生命週期與資料保存

-