如何检测swift中第一次运行IteratorProtocol?

问题描述 投票:1回答:1

试图检测第一次运行Iterator协议。在下面的例子中,我试图从Zero开始打印Fibonacci系列,但它从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)))

可以对上面的代码进行哪些修改来检测第一次运行?

ios swift algorithm fibonacci iterator-protocol
1个回答
1
投票

要回答你的逐字问题:你可以添加一个布尔变量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]

但是对于这个问题有更优雅的解决方案。您可以在返回当前值后“延迟”ab的更新:

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]

或者 - 或许更简单 - 改变初始值(使用Fibonacci数字也为负指数定义的事实):

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()
© www.soinside.com 2019 - 2024. All rights reserved.