如何在 Swift 中创建生成器?

Mac*_*eus 5 generator swift

我可以在 Swift 中创建一个生成器吗?

使用迭代器,我需要存储中间结果,例如:

struct Countdown: IteratorProtocol, Sequence {

    private var value = 0

    init(start: Int) {
        self.value = start
    }

    mutating func next() -> Int? {
        let nextNumber = value - 1
        if nextNumber < 0 {
            return nil
        }

        value -= 1

        return nextNumber
    }
}

for i in Countdown(start: 3) {
    print(i)
} // print 1 2 3
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我需要存储value.

在我的情况下,我想使用生成器而不是迭代器,因为我不想将序列的中间结果存储在每个next.

Wat*_*rds 7

从 Python 开始,理解生成器的工作原理(以及为什么它们在 swift 中不那么重要)是很困难的。

在 Swift v2.1 之前,有一个名为 GeneratorType 的协议。这在 Swift v3.0+ 中更名为 IteratorProtocol。你可以遵循这个协议来创建你自己的对象,这些对象可以像在 Python 中所做的那样进行即时计算。

更多信息可以在 Apple 文档中找到:IteratorProtocol

IteratorProtocol 页面的一个简单示例:

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
    }
}

let threeTwoOne = Countdown(start: 3)
for count in threeTwoOne {
    print("\(count)...")
}
// Prints "3..."
// Prints "2..."
// Prints "1..."
Run Code Online (Sandbox Code Playgroud)

但是,您需要考虑为什么要使用生成器:

Swift 会自动执行“写入时复制”的操作。这意味着许多使用 Python 生成器来避免对象集合(数组、列表、字典等)的大量复制成本的情况在 Swift 中是不必要的。您可以通过使用使用写入时复制的类型之一免费获得此功能。

Swift 中哪些值类型支持写时复制?

也可以使用包装器强制几乎所有对象在写入时进行复制,即使它不是集合的一部分:

如何制作具有写时复制语义的容器?

swift 中的优化通常意味着您不必编写生成器。如果您确实需要(通常是因为数据量大,科学计算),则可以如上所述。