當前位置: 首頁>>編程示例 >>用法及示例精選 >>正文


Swift IteratorProtocol用法及代碼示例

協議

IteratorProtocol

一種一次提供一個序列值的類型。

聲明

protocol IteratorProtocol<Element>

概述

IteratorProtocol 協議與Sequence 協議緊密相連。序列通過創建一個迭代器來提供對其元素的訪問,該迭代器跟蹤其迭代過程並在它通過序列時一次返回一個元素。

每當您使用帶有數組、集合或任何其他集合或序列的 for - in 循環時,您都在使用該類型的迭代器。 Swift 在內部使用序列或集合的迭代器來啟用 for - in 循環語言結構。

直接使用序列的迭代器可以讓您以與使用 for - in 循環迭代該序列相同的順序訪問相同的元素。例如,您通常可以使用 for - in 循環來打印數組中的每個元素。


let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
for animal in animals {
    print(animal)
}
// Prints "Antelope"
// Prints "Butterfly"
// Prints "Camel"
// Prints "Dolphin"

在幕後,Swift 使用 animals 數組的迭代器來循環數組的內容。


var animalIterator = animals.makeIterator()
while let animal = animalIterator.next() {
    print(animal)
}
// Prints "Antelope"
// Prints "Butterfly"
// Prints "Camel"
// Prints "Dolphin"

animals.makeIterator() 的調用返回數組迭代器的一個實例。接下來,while 循環重複調用迭代器的 next() 方法,綁定每個返回到 animal 的元素,並在 next() 方法返回 nil 時退出。

直接使用迭代器

您很少需要直接使用迭代器,因為 for - in 循環是在 Swift 中遍曆序列的更慣用的方法。然而,一些算法可能需要直接使用迭代器。

一個示例是reduce1(_:) 方法。與標準庫中定義的reduce(_:_:) 方法類似,該方法采用初始值和組合閉包,reduce1(_:) 使用序列的第一個元素作為初始值。

這是reduce1(_:) 方法的實現。序列的迭代器直接用於在遍曆序列的其餘部分之前檢索初始值。


extension Sequence {
    func reduce1(
        _ nextPartialResult: (Element, Element) -> Element
    ) -> Element?
    {
        var i = makeIterator()
        guard var accumulated = i.next() else {
            return nil
        }


        while let element = i.next() {
            accumulated = nextPartialResult(accumulated, element)
        }
        return accumulated
    }
}

reduce1(_:) 方法使某些類型的序列操作更簡單。下麵以前麵介紹的animals數組為例,說明如何查找序列中最長的字符串:


let longestAnimal = animals.reduce1 { current, element in
    if current.count > element.count {
        return current
    } else {
        return element
    }
}
print(longestAnimal)
// Prints Optional("Butterfly")

使用多個迭代器

每當您在單個序列上使用多個迭代器(或 for - in 循環)時,請確保您知道特定序列支持重複迭代,因為您知道它的具體類型或因為序列也被限製為 Collection 協議。

通過對序列的 makeIterator() 方法的單獨調用而不是通過複製來獲取每個單獨的迭代器。複製迭代器是安全的,但通過調用 next() 方法推進迭代器的一個副本可能會使該迭代器的其他副本無效。 for - in 循環在這方麵是安全的。

將IteratorProtocol 一致性添加到您的類型

實現符合IteratorProtocol 的迭代器很簡單。聲明一個 next() 方法,該方法在相關序列中前進一步並返回當前元素。當序列耗盡時,next() 方法返回 nil

例如,考慮一個自定義 Countdown 序列。您可以使用起始整數初始化Countdown 序列,然後將計數迭代到零。 Countdown 結構的定義很簡短:它隻包含起始計數和Sequence 協議所需的makeIterator() 方法。


struct Countdown: Sequence {
    let start: Int


    func makeIterator() -> CountdownIterator {
        return CountdownIterator(self)
    }
}

makeIterator() 方法返回另一個自定義類型,一個名為 CountdownIterator 的迭代器。 CountdownIterator 類型跟蹤它正在迭代的 Countdown 序列以及它返回值的次數。


struct CountdownIterator: IteratorProtocol {
    let countdown: Countdown
    var times = 0


    init(_ countdown: Countdown) {
        self.countdown = countdown
    }


    mutating func next() -> Int? {
        let nextNumber = countdown.start - times
        guard nextNumber > 0
            else { return nil }


        times += 1
        return nextNumber
    }
}

每次在 CountdownIterator 實例上調用 next() 方法時,它都會計算新的下一個值,檢查它是否已達到零,然後返回數字,如果迭代器完成返回元素,則返回 nil的序列。

創建和迭代 Countdown 序列使用 CountdownIterator 來處理迭代。


let threeTwoOne = Countdown(start: 3)
for count in threeTwoOne {
    print("\(count)...")
}
// Prints "3..."
// Prints "2..."
// Prints "1..."

可用版本

iOS 8.0+, iPadOS 8.0+, macOS 10.10+, Mac Catalyst 13.0+, tvOS 9.0+, watchOS 2.0+

相關用法


注:本文由純淨天空篩選整理自apple.com大神的英文原創作品 IteratorProtocol。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。