IteratorProtocol
協(xié)議和Sequence
的聯(lián)系是非常緊密的。序列通過創(chuàng)建一個迭代器來訪問它們的元素,迭代器跟蹤它的迭代過程并在它通過序列前進時每次返回一個元素。
當你在array
, set
, 或者其他集合和序列使用for - in
的時候就會用到這個類型的迭代器冬殃。swift使用隊列或者集合的內(nèi)部迭代器以便使用for - in
這種語言結(jié)構(gòu)。
直接使用迭代器遍歷元素和用for - in
遍歷同一個數(shù)組是等價的叁怪。比如你使用for - in
遍歷數(shù)組["Antelope", "Butterfly", "Camel", "Dolphin"]
let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
for animal in animals {
print(animal)
}
// Prints "Antelope"
// Prints "Butterfly"
// Prints "Camel"
// Prints "Dolphin"
但是在他的底層使用的是Array
的迭代器遍歷這個數(shù)組
var animalIterator = animals.makeIterator()
while let animal = animalIterator.next() {
print(animal)
}
// Prints "Antelope"
// Prints "Butterfly"
// Prints "Camel"
// Prints "Dolphin"
animals.makeIterator()
返回當前數(shù)組的迭代器审葬,下一步當while
循環(huán)調(diào)用了迭代器的next()
方法時,元素就被一個一個取出來了奕谭,直到next()
返回nil
的時候退出涣觉。
直接使用迭代器
- 在通常的情況下我們直接使用
for-in
就可以滿足,但是在某些場合下我們會直接使用迭代器血柳。 - 一個例子就是
reduce1(_:)
函數(shù)官册,類似于標準庫中定義的reduce(_:_:)
函數(shù)(帶有一個初始值和一個結(jié)合閉包),reduce1(_:)
需要用到序列的第一個元素作為初始值难捌。 - 下面就是
reduce1(_:)
的一個實現(xiàn)膝宁,直接使用迭代器來取初始值
extension Sequence {
func reduce1(_ nextPartialResult: (Iterator.Element, Iterator.Element) -> Iterator.Element) -> Iterator.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
數(shù)組中最長的字符串:
let longestAnimal = animals.reduce1 { current, element in
if current.characters.count > element.characters.count {
return current
} else {
return element
}
}
// print(longestAnimal)
// Prints "Butterfly"
使用多個迭代器
每當你在一個隊列使用多個迭代器(或者for-in
)時根吁, 請確保特殊的隊列能支持重復(fù)迭代员淫,或者確保你知道他的具體類型,或者確保它遵守Collection
協(xié)議击敌。
從各自獨立的迭代器到調(diào)用各自獨立的迭代器的序列的makeIterator()
方法介返,而不是通過復(fù)制。復(fù)制迭代器是安全的,但是調(diào)用復(fù)制后的迭代器的next()
方法圣蝎,就有可能會使其他這個迭代器的副本失效刃宵。for-in
循環(huán)則是安全的
....
在自定義類型中合適的添加IteratorProtocol
協(xié)議
實現(xiàn)一個合適迭代器很簡單,定義一個next()
函數(shù)徘公,當前進一步的時候返回當前的元素组去,當這個序列結(jié)束,next()
函數(shù)返回nil
步淹。
例如,假設(shè)我們有個Countdown
序列诚撵,你可以用一個起始數(shù)字初始化這個序列缭裆,然后迭代到0。這個數(shù)據(jù)結(jié)構(gòu)定義的很短:它僅僅只有起始數(shù)和Sequence
需要的makeIterator()
方法寿烟。
struct Countdown: Sequence {
let start: Int
func makeIterator() -> CountdownIterator {
return CountdownIterator(self)
}
}
makeIterator()
返回一個自定義迭代器CountdownIterator
澈驼。CountdownIterator
追蹤Countdown
序列的迭代和它返回值的次數(shù)
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
}
}
每次next()
方法是被當前CountdownIterator
調(diào)用,他計算下一個新的數(shù)組筛武,檢查多久會減少到0缝其,然后返回數(shù)字,或者在迭代器返回完序列的元素之后返回nil
調(diào)用:
let threeTwoOne = Countdown(start: 3)
for count in threeTwoOne {
print("\(count)...")
}
// Prints "3..."
// Prints "2..."
// Prints "1..."
...