Swift 3 中的最小工作迭代器协议/序列

Minimal working IteratorProtocol / Sequence in Swift 3

我发现在 Swift 3 中找到使用 Sequence / IteratorProtocol 的“工作文档”非常困难。少数 tutorials/articles 似乎是针对较旧的 Swift .

想象一个名为 DLList ...

的玩具双向链表 class
public class Node
    {
    // whatever "thing" you have a group of, this is that "thing"
    }
public class DLList
    {
    // toy linked list class here
    // so this is a group of "node" in this example
    }

我相信以下代表了最简单(?)、正确的方法,总之,您可以在 for 结构中使用 DLList

第一步,让你的DLList符合DLList:Sequence

public class DLList:Sequence
    {
    // toy linked list class here
    
    public func makeIterator() -> DLListIterator
        {
        return DLListIterator(self)
        }
    }

似乎您所要做的就是添加 makeIterator 调用。

第二步,写你的迭代器,符合IteratorProtocol

由于 class 是 DLList,我们将其称为 DLListIterator。好像

1,你必须有一个“init”,它基本上是 class 组的问题

2,你必须有一个 next 调用,它必须 return 与你的组 class.

神奇相关的“事物”之一
public class DLListIterator:IteratorProtocol
    {
    var dll:DLList  // you must know the group in question
    var pointer:Node?  // you must know where you are
    
    init(_ dll:DLList)
        {
        // so note those two items
        self.dll = dll
        self.pointer = dll.firstOne
        }
    
    public func next() -> Node?
        {
        // return the next one; careful to return nil at end.
        let thisOne = self.pointer
        self.pointer = self.pointer?.nextOne
        return thisOne
        }
    }

这似乎工作得很好。也就是说,你现在可以去

var d:DLList = DLList()
for n in d
 {
 print or whatever n
 }

您可以使用 e = d.filter( {d.item blah} ) 等等 - 太棒了。

问题 - 关于关联类型的讨论很多。在第 1 部分中,您是否以某种方式明确 state/add “关联类型”?即使没有明确要求你会怎么做?这个关联型业务是什么鬼?

问题 - 在第二部分中,我完全不明白它是如何“知道”Node 是与 DLList 相关的“事物”的。有没有办法让它明确,或者我不明白什么?

Swiftness 而且,整个事情好像不太Swifty。仅仅为了添加迭代器输出而做所有这些似乎令人难以置信。在 Swift3 中,对于真正的 class,有没有更快捷的方法? (不是像“倒计时数字”这样愚蠢的例子。)

最后一个问题 我高兴地提到上面现在允许和.filter。事实上,我的示例是否“完整”——我现在可以用 DLList 做所有“迭代器方面”的事情吗,在 Swift 中通常可以做的事情——我是否可能“忘记了一些功能”或者?要使 DLList 成为真正优秀的迭代器,还有更多工作要做吗?

这一切都通过类型推断很好地工作(在 Swift 中非常强大)。

例如IteratorProtocol只有一个要求,就是next() -> Element?方法。如果您只用 Cmd 键单击 XCode 中的 IteratorProtocol:

,您可以看到以下内容
public protocol IteratorProtocol {
    associatedtype Element
    public mutating func next() -> Self.Element?
}

因此,如果您声明一个类型以符合 IteratorProtocol 并提供某些 next() -> Foo? 的实现,那么 Swift 立即推断出 Foo 必须是 Element.

当然,您可以通过以下方式明确声明:

public class DLListIterator: IteratorProtocol {
    public typealias Element = Node

    public func next() -> Element? {
        // ...
    }
}

而且,是的,一旦您实现了两者(SequenceIterator,也就是说)您就可以做其他序列可以做的所有事情。这一切都归功于默认协议实现。

为了符合 Sequence,您需要提供 makeIterator(),而反过来又必须提供 next(),所有这些样板文件是否 Swifty或者不是.. 我认为这更多是基于意见的。有时,您可以实现 Sequence 而无需继续实现 IteratorProtocol (例如,当您实现包装器时)。所以,拆分对我来说确实有意义。

这是我的最小示例

class TestIter: Sequence, IteratorProtocol {
    var mylist:[Int] = [1,2,3,4,5,6]    // contents
    var curPos = 0                      // var for iterator

    func makeIterator() -> TestIter {
        curPos = 0
        return self
    }

    public typealias Element = Int
    func next() -> Element? {
        if curPos < mylist.count {
            let oldPos = curPos
            curPos += 1
            return mylist[oldPos]
        }
        return nil
    }

}

let testIt = TestIter()
for i in testIt {
    print("i:\(i)")
}