解释Swift迭代器 [英] Explain Swift Iterators

查看:80
本文介绍了解释Swift迭代器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于如何在Swift中制作生成器(或显然在Swift中称为迭代器)的最新指南很少,特别是如果您是该语言的新手.为什么生成器类型如此之多,例如AnyIteratorUnfoldSequence?为什么应该从单个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 Ints or Arrays of Ints, 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.

推荐答案

是的,AnyIteratornext()方法调用给定的闭包. 并且在您的代码中,该闭包在每次调用时返回相同的第一个元素,因为它不记得已经返回了哪些元素.

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 segmentyield 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆