Чтобы ответить на ваш дословный вопрос: вы можете добавить логическую переменную
firstRun
для обнаружения первого вызова метода next()
:
class FibIterator : IteratorProtocol {
var firstRun = true
var (a, b) = (0, 1)
func next() -> Int? {
if firstRun {
firstRun = false
return 0
}
(a, b) = (b, a + b)
return a
}
}
let fibs = AnySequence { FibIterator() }
print(Array(fibs.prefix(10))) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Но есть и более элегантные решения этой проблемы.
Вы можете «отложить» обновление a
и b
, чтобы сделать после возврата
текущее значение:
class FibIterator : IteratorProtocol {
var (a, b) = (0, 1)
func next() -> Int? {
defer { (a, b) = (b, a + b) }
return a
}
}
let fibs = AnySequence { FibIterator() }
print(Array(fibs.prefix(10))) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
или - возможно, проще - изменить начальные значения (используя факт
что числа Фибоначчи определены и для отрицательных индексов):
class FibIterator : IteratorProtocol {
var (a, b) = (1, 0) // (Fib(-1), Fib(0))
func next() -> Int? {
(a, b) = (b, a + b)
return a
}
}
let fibs = AnySequence { FibIterator() }
print(Array(fibs.prefix(10))) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Обратите внимание, что если вы заявляете о соответствии протоколу Sequence
тогда вам не нужна оболочка AnySequence
(по умолчанию
реализация makeIterator()
для типов, соответствующих
IteratorProtocol
). Также типы значений обычно предпочтительнее,
поэтому - если не требуется ссылочная семантика - вы можете сделать это struct
:
struct FibSequence : Sequence, IteratorProtocol {
var (a, b) = (1, 0) // (Fib(-1), Fib(0))
mutating func next() -> Int? {
(a, b) = (b, a + b)
return a
}
}
let fibs = FibSequence()