解释Swift迭代器 [英] Explain Swift Iterators
问题描述
关于如何在Swift中制作生成器(或显然在Swift中称为迭代器)的最新指南很少,特别是如果您是该语言的新手.为什么生成器类型如此之多,例如AnyIterator
和UnfoldSequence
?为什么应该从单个Int
s或Int
s数组的序列产生的以下代码不起作用?
There’s very little up-to-date guidance on how to make generators in Swift (or iterators as they’re apparently called in Swift), especially if you are new to the language. Why are there so many generator types like AnyIterator
and UnfoldSequence
? Why doesn’t the following code, which should yield from a sequence of either individual Int
s or Arrays of Int
s, work?
func chain(_ segments: Any...) -> AnyIterator<Int>{
return AnyIterator<Int> {
for segment in segments {
switch segment {
case let segment as Int:
return segment
case let segment as [Int]:
for i in segment {
return i
}
default:
return nil
}
}
return nil
}
}
let G = chain(array1, 42, array2)
while let g = G.next() {
print(g)
}
按照我的理解,AnyIterator
应该在{}
中使用闭包,然后在返回的生成器中将其转换为.next()
方法,但似乎没有用.还是应该像此问题中那样使用UnfoldSequence
.我很困惑.
The way I understand it, AnyIterator
is supposed to take the closure in the {}
s and turn it into the .next()
method in the returned generator, but it doesn’t seem to be working. Or should I be using UnfoldSequence
like in this question instead. I’m very confused.
推荐答案
是的,AnyIterator
的next()
方法调用给定的闭包.
并且在您的代码中,该闭包在每次调用时返回相同的第一个元素,因为它不记得已经返回了哪些元素.
Yes, the next()
method of AnyIterator
calls the given closure.
And in your code, that closure returns the same first element on each call, because it does not remember what elements have been returned already.
如果Swift有像Python或C#这样的yield
语句,那么事情会更容易:您可以yield segment
或yield i
并完成.
If Swift had a yield
statement like Python or C# then things would be easier: you could yield segment
or yield i
and are done.
但是–不幸的是? – Swift没有yield
语句,这意味着
闭包必须显式管理某种状态才能恢复迭代
以及每次通话的下一个元素.
But – unfortunately? – Swift has no yield
statement, which means
that the closure must explicitly manage some state in order to resume the iteration
with the next element on each call.
一种可能性是维持两个指数,一个用于 当前段,其中一个用于当前元素 一个细分(如果它是一个数组):
One possibility would be to maintain two indices, one for the current segment and one for the current element within a segment if that is an array:
func chain(_ segments: Any...) -> AnyIterator<Int> {
var currentSegment = 0 // index of current segment
var currentElement = 0 // index of current element within current segment
return AnyIterator<Int> {
while currentSegment < segments.count {
let next = segments[currentSegment]
switch next {
case let value as Int:
currentSegment += 1
return value
case let segment as [Int]:
if currentElement < segment.count {
let val = segment[currentElement]
currentElement += 1
return val
}
currentSegment += 1
currentElement = 0
default:
return nil
}
}
return nil
}
}
这可以推广到任意嵌套的数组:
This can be generalized to arbitrarily nested arrays:
func chain(_ segments: Any...) -> AnyIterator<Int> {
var stack: [(Any, Int)] = [(segments, 0)]
return AnyIterator<Int> {
while let (next, idx) = stack.popLast() {
switch next {
case let value as Int:
return value
case let segments as [Any]:
if idx < segments.count {
stack.append((segments, idx + 1))
stack.append((segments[idx], 0))
}
default:
return nil
}
}
return nil
}
}
还有待处理的数组与堆栈一起 他们当前的索引.数组本身不会被修改, 这样副本就便宜了.
The still-to-be-processed arrays are on the stack together with their current index. The arrays themselves are not modified, so that the copy is cheap.
示例:
let G = chain([1, 2, [3]], 4, [5, 6, [], 7])
while let g = G.next() {
print(g)
}
// 1 2 3 4 5 6 7
另请参见在Swift中为简单树结构实现递归生成器了解更多 递归枚举树状结构的方法.
See also Implementing recursive generator for simple tree structure in Swift for more approaches to recursively enumerate a tree-like structure.
这篇关于解释Swift迭代器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!