1

Trying to detect the first run of an Iterator protocol. In the example below I'm trying to start printing Fibonacci series from Zero but it starts from One:

class FibIterator : IteratorProtocol {
var (a, b) = (0, 1)

func next() -> Int? {
    (a, b) = (b, a + b)
    return a
}
}

let fibs = AnySequence{FibIterator()}

print(Array(fibs.prefix(10)))

What modifications can be made to the above code to detect the first run?

4

1 回答 1

1

To answer your verbatim question: You can add a boolean variable firstRun to detect the first call of the next() method:

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]

But there are more elegant solutions for this problem. You can “defer” the update of a and b to be done after returning the current value:

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]

or – perhaps simpler – change the initial values (using the fact that the Fibonacci numbers are defined for negative indices as well):

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]

Note that if you declare conformance to the Sequence protocol then you don't need the AnySequence wrapper (there is a default implementation of makeIterator() for types conforming to IteratorProtocol). Also value types are generally preferred, so – unless the reference semantics is needed – you can make it a 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()
于 2018-08-30T15:50:46.230 回答