iteratorprotocol
协议是紧密联系在一起的序列Sequence
协议。序列通过创建一个迭代器来访问它们的元素,该迭代器跟踪其迭代过程,每次通过序列时返回一个元素。
无论何时使用数组、集合或任何其他集合或序列中的“在”for-in中,都使用该类型的迭代器。SWIFT在内部使用序列或集合的迭代器,以便在“for-in”语言构造中启用。
直接使用序列的迭代器使您能够以与'for - in'顺序相同的顺序访问相同的元素。例如,您可能通常使用“在”for - in ”来打印数组中的每一个元素。
let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
for animal in animals {
print(animal)
}
在后台,Swift使用“动物”数组的迭代器循环遍历数组的内容。
let animals = ["Antelope", "Butterfly", "Camel", "Dolphin"]
var animalIterator = animals.makeIterator()
while let animal = animalIterator.next() {
print(animal)
}
命令 animals.makeiterator()
返回数组的迭代器的实例。接下来的while
循环反复的调用迭代器的next()
方法,结合每个元素,返回animal
,当退出时next()
方法返回nil
。
========================
您很少需要直接使用迭代器,因为"for - in 循环"是更为符合语言习惯的快速遍历序列的方法。然而,有些算法可能要求直接迭代器使用。
一个例子是reduce1(_:)
方法。类似的reduce(_: _:)
方法在标准库定义的,这需要一个初始值和结合封闭,reduce1(_:)
使用序列的第一个元素作为初始值。
这里的reduce1(_:)
方法。序列的迭代器直接用于在循环其余的循环之前检索初始值。
extension Sequence {
func reduce1(_ nextPartialResult: (Iterator.Element, Iterator.Element) -> Iterator.Element ) -> Iterator.Element {
var i = makeIterator()
guard var accumulated = i.next() else {
return (() -> ()).self as! Self.Iterator.Element
}
while let element = i.next() {
accumulated = nextPartialResult(accumulated, element)
}
return accumulated
}
}
// 注意: 在使用 Playground 的时候 " guard else " 的 return 如果返回 nil 报错
Playground execution failed: error: WYPlayground.playground:16:20: error: nil is incompatible with return type 'Self.Iterator.Element'
return nil
^
// 改成
guard var accumulated = i.next() else {
return (() -> ()).self as! Self.Iterator.Element
}
reduce1(_:)
方法使某些种类的序列操作变得简单。下面是使用前面介绍的"animals"数组来查找序列中最长的字符串:
let logestAnimal = animals.reduce1 { (current, element) -> String in
if current.characters.count > element.characters.count{
return current
} else {
return element
}
}
print( logestAnimal)
打印结果:
Butterfly
当您在一个序列中使用多个迭代器(或 for - in 循环),请确保您知道特定的序列支持重复迭代,或者因为您知道它的具体类型,或者因为该序列也受限于 "Collection" 协议。
从单独的调用获取每个单独的迭代器到序列的“makeIterator()”方法,而不是复制。复制迭代器是安全的,但是通过调用其“next()”方法来推送一个迭代器的一个副本可能会使该迭代器的其他副本无效。 for - in
循环在这方面是安全的。
==============================
添加 IteratorProtocol 符合你的类型
实现符合“IteratorProtocol”的迭代器很简单。 声明一个next()
方法,前进相关序列中的一个步骤并返回当前元素。 当序列耗尽时,next()
方法返回nil
。
例如,考虑一个自定义的“倒计时”序列。 您可以使用起始整数初始化“倒计时”序列,然后将计数倒数计算为零。 “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”序列中创建和迭代使用“Countdown Iterator”来处理迭代。
let threeTwoOne = Countdown(start: 3)
for count in threeTwoOne {
print("\(count)...")
}
/*
3...
2...
1...
*/
public mutating func next() -> Self.Element?
前进到下一个元素并返回它,如果没有下一个元素存在,则为“nil”。 重复调用此方法按顺序返回底层序列的所有元素。 一旦序列用完了元素,所有后续调用都返回nil
。 如果此迭代器的任何其他副本已调用其“next()”方法,则不得调用此方法。 以下示例显示了如何显式地使用迭代器来模拟for
-in
循环。 首先,检索序列的迭代器,然后调用迭代器的“next()”方法,直到它返回“nil”。
let numbers = [2,3,5,7]
var numbersIterator = numbers.makeIterator()
while let num = numbersIterator.next() {
print(num)
}
/*
2
3
5
7
*/
网友评论