struct Stack<Element> { var items = [Element]() mutating func push(item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() } }
このジェネリック構造体を拡張してみる。
ジェネリック型を拡張する際は、extensionの定義の一部としてパラメータリストを与える必要がない。
その代わり、originalの型定義からの型パラメータリストはextensionのbody内で利用でき、オリジナルの型パラメータ名はオリジナルの定義からの型パラメータへの参照に利用できる。
以下で、読み込み専用のcomputed プロパティtopItemを定義している。
extension Stack { var topItem: Element? { return items.isEmpty ? nil : items[items.count - 1] } }
Adding Protocol Conformance with an Extension
class Dice { let sides: Int let generator: RandomNumberGenerator init(sides: Int, generator: RandomNumberGenerator) { self.sides = sides self.generator = generator } func roll() -> Int { return Int(generator.random() * Double(sides)) + 1 } } protocol TextRepresentable { var textualDescription: String { get } }
DiceクラスをTextRepresentableプロトコルに適合したクラスにextensionしてみる。
extension Dice: TextRepresentable { var textualDescription: String { return "A \(sides)-sided dice" } }
Protocol Inheritance
以下のようにプロトコルは継承できる。
protocol PrettyTextRepresentable: TextRepresentable { var prettyTextualDescription: String { get } }
Protocol Extensions
プロトコルに対して、メソッド実装やプロパティ実装をextensionできる。
protocol RandomNumberGenerator { func random() -> Double } extension RandomNumberGenerator { func randomBool() -> Bool { return random() > 0.5 } }
プロトコルは引数と戻り値が決まっているので、extensionで追加したメソッドやプロパティはその関数の呼び出しを利用した形の実装となっているところがミソである。
Associated Types
ItemTypeをAssociated Typeとして定義したContainerプロトコルである。
protocol Container { typealias ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } }
このプロトコルに準拠した構造体は以下のように作る。
Associated TypeであるItemTypeの型を固定しているところがミソである。
struct IntStack: Container { // original IntStack implementation var items = [Int]() mutating func push(item: Int) { items.append(item) } mutating func pop() -> Int { return items.removeLast() } // conformance to the Container protocol typealias ItemType = Int // <- ここでItemTypeの型を固定している mutating func append(item: Int) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> Int { return items[i] } }