スウィフト-ジェネリック

7605 ワード

ジェネリックコードを使用すると、柔軟で再利用可能な(重複する)関数と、任意の型で動作する型を定義できます.
  • 配列、セット、および辞書はSwiftのジェネリック型です.
  • 汎用関数


    汎用関数は任意の型で動作できます.関数のジェネリックバージョンでは、実際の型名の代わりにプレースホルダ型の名前を使用します.プレースホルダの代わりに使用する実際の型は、ジェネリック関数が呼び出されるたびに決定されます.
  • 型パラメーターはプレースホルダ型を指定し、名前を付け、関数の名前の直後に、1組の対応する角括弧の間に書き込まれます.コンマで区切られた複数の型パラメーターを指定できます.
  • 例:
    func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
        let temporaryA = a
        a = b
        b = temporaryA
    }
    

    ジェネリックタイプ


    これらは任意の型で動作できるカスタムクラス、構造、および列挙体です.
    例:
    struct Stack<Element> {
        var items: [Element] = []
        mutating func push(_ item: Element) {
            items.append(item)
        }
        mutating func pop() -> Element {
            return items.removeLast()
        }
    }
    
    var stackOfStrings = Stack<String>()
    stackOfStrings.push("uno")
    stackOfStrings.push("dos")
    
  • ジェネリック型を拡張すると、拡張モジュールの定義の一部として型パラメーターリストを提供しません.代わりに、元の型定義の型パラメーターリストが拡張子の本体内で使用できます.
  • 例:
    extension Stack {
        var topItem: Element? {
            return items.isEmpty ? nil : items[items.count - 1]
        }
    }
    
    一般的なタイプの
  • 拡張はまた、拡張型のインスタンスがジェネリックWhere句を使用して新しい機能を得るために満たす必要がある要件を含めることができます.
  • 型制約


    型制約は、型パラメーターが特定のクラスから継承しなければならないか、特定のプロトコルまたはプロトコル構成に従う必要があることを指定します.
    SynatX :func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
    // function body goes here
    }
    ここでパラメータには型制約があります.
    Someclass のサブクラスであるために、
  • T
    プロトコルsomeso
  • に従う
  • U
    例:
    func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
        for (index, value) in array.enumerated() {
            if value == valueToFind {
                return index
            }
        }
        return nil
    }
    

    関連タイプ


    関連付けられた型は、プロトコルの一部として使われるタイプにプレースホルダ名を与えます.プロトコルが採用されるまで、その関連型のために使用する実際のタイプは指定されません.
    関連するタイプは、関連付けられているタイプを指定します.
  • 例:
    protocol Container {
        associatedtype Item
        mutating func append(_ item: Item)
        var count: Int { get }
        subscript(i: Int) -> Item { get }
    }
    
    struct Stack<Element>: Container {
        // original Stack<Element> implementation
        var items: [Element] = []
        mutating func push(_ item: Element) {
            items.append(item)
        }
        mutating func pop() -> Element {
            return items.removeLast()
        }
        // conformance to the Container protocol
        mutating func append(_ item: Element) {
            self.push(item)
        }
        var count: Int {
            return items.count
        }
        subscript(i: Int) -> Element {
            return items[i]
        }
    }
    
    既存のタイプは、プロトコルに適合性を加えるために延長されることができます.例:
    extension Array: Container {}
    

  • タイプ制約は、適合型がそれらの制約を満たすことを必要とするプロトコルの関連型に追加できます.
    例:
  • protocol Container {
        associatedtype Item: Equatable
        mutating func append(_ item: Item)
        var count: Int { get }
        subscript(i: Int) -> Item { get }
    }
    
  • プロトコルは、それ自身の要件の一部として現れることができます.
    例:
  • protocol SuffixableContainer: Container {
        associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
        func suffix(_ size: Int) -> Suffix
    }
    
    サフィックスには2つの制約があります.これは、SuffixableContainerプロトコル(現在定義されているプロトコル)に準拠しなければならず、その型の型はコンテナの項目型と同じにする必要があります.
    例:
    extension Stack: SuffixableContainer {
        func suffix(_ size: Int) -> Stack {
            var result = Stack()
            for index in (count-size)..<count {
                result.append(self[index])
            }
            return result
        }
        // Inferred that Suffix is Stack.
    }
    var stackOfInts = Stack<Int>()
    stackOfInts.append(10)
    stackOfInts.append(20)
    stackOfInts.append(30)
    let suffix = stackOfInts.suffix(2)
    

    一般的な条項


    一般的な関数、サブスクリプト、または型に関連付けられている型パラメーターの要件を定義するために使用される型制約.
    関連する型の要件を定義するには、Generic WHERE句を定義します.一般的なWHERE句で、
  • 関連タイプはあるプロトコルに従わなければなりません、あるいは、
  • 特定のタイプパラメタと関連タイプは同じでなければなりません.
  • 例:
    func allItemsMatch<C1: Container, C2: Container>
        (_ someContainer: C1, _ anotherContainer: C2) -> Bool
        where C1.Item == C2.Item, C1.Item: Equatable {
    
            // Check that both containers contain the same number of items.
            if someContainer.count != anotherContainer.count {
                return false
            }
    
            // Check each pair of items to see if they're equivalent.
            for i in 0..<someContainer.count {
                if someContainer[i] != anotherContainer[i] {
                    return false
                }
            }
    
            // All items match, so return true.
            return true
    }
    
    var stackOfStrings = Stack<String>()
    stackOfStrings.push("uno")
    stackOfStrings.push("dos")
    stackOfStrings.push("tres")
    
    var arrayOfStrings = ["uno", "dos", "tres"]
    
    if allItemsMatch(stackOfStrings, arrayOfStrings) {
        print("All items match.")
    } else {
        print("Not all items match.")
    } // Prints "All items match."
    
    ここでは、スタックと配列が異なる型の場合でも、両者はコンテナープロトコルに準拠し、両方とも同じ型の値を含んでいます.
  • 一般的なWHERE句は拡張子の一部です.
  • 例:
    extension Stack where Element: Equatable {
        func isTop(_ item: Element) -> Bool {
            guard let topItem = items.last else {
                return false
            }
            return topItem == item
        }
    }
    

    文脈のある節


    ジェネリックWHERE句は、ジェネリック型の制約を持たない宣言の一部として含めることができます.
    extension Container {
        func average() -> Double where Item == Int {
            var sum = 0.0
            for index in 0..<count {
                sum += Double(self[index])
            }
            return sum / Double(count)
        }
        func endsWith(_ item: Item) -> Bool where Item: Equatable {
            return count >= 1 && self[count-1] == item
        }
    }
    

    extension Container where Item == Int {
        func average() -> Double {
            var sum = 0.0
            for index in 0..<count {
                sum += Double(self[index])
            }
            return sum / Double(count)
        }
    }
    extension Container where Item: Equatable {
        func endsWith(_ item: Item) -> Bool {
            return count >= 1 && self[count-1] == item
        }
    }
    

    一般的なWHERE句を使用した型


    一般的なWHERE句は関連する型に含めることができます.
    例:
    protocol Container {
        associatedtype Item
        mutating func append(_ item: Item)
        var count: Int { get }
        subscript(i: Int) -> Item { get }
    
        associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
        func makeIterator() -> Iterator
    }
    

    一般的な購読


    添字は一般的であり、一般的なwhere句を含めることができます.
    例:
    extension Container {
        subscript<Indices: Sequence>(indices: Indices) -> [Item]
            where Indices.Iterator.Element == Int {
                var result: [Item] = []
                for index in indices {
                    result.append(self[index])
                }
                return result
        }
    }
    
    一般的なWHERE句では、シーケンスのイテレータがint型の要素を通過する必要があります.これは、シーケンス内のインデックスがコンテナに使用されるインデックスと同じ型であることを保証します.