Последовательности предоставляют доступ к своим элементам путём создания итератора, который отслеживает процесс итерации и возвращает один элемент за раз по мере продвижения по последовательности.
Каждый раз, когда вы используете цикл for in с массивом, множеством или любой другой коллекцией или последовательностью, вы фактически используете итератор этого типа. Swift использует итератор последовательности или коллекции внутренне для реализации конструкции языка 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.
Реализовать итератор, соответствующий протоколу IteratorProtocol, довольно просто.
Нужно объявить метод next(), который делает один шаг в связанной последовательности и возвращает текущий элемент. Когда последовательность заканчивается, метод next() должен возвращать nil.
Например, рассмотрим пользовательскую последовательность Countdown.
Вы можете инициализировать последовательность Countdown с некоторого начального целого числа и затем итерироваться по ней в обратном порядке до нуля.
Определение структуры Countdown короткое:
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
}
}
Каждый раз при вызове метода next() у экземпляра CountdownIterator, он вычисляет следующее значение, проверяет, достиг ли нуля, и затем возвращает либо число, либо nil, если итератор завершил выдачу элементов последовательности.
Создание и перебор последовательности Countdown использует CountdownIterator для управления итерацией.
let threeTwoOne = Countdown(start: 3)
for count in threeTwoOne {
print("\\(count)...")
}
// Prints "3..."
// Prints "2..."
// Prints "1..."