【问题标题】:Minimal working IteratorProtocol / Sequence in Swift 3Swift 3 中最小的工作迭代器协议/序列
【发布时间】:2016-10-31 21:18:44
【问题描述】:

我发现很难找到在 Swift 3 中使用 Sequence / IteratorProtocol 的“工作文档”。那里的一些教程/文章似乎是针对旧版 Swift 的。

想象一个名为DLList 的玩具双向链表类...

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

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

1,你必须有一个“init”,它基本上接受有问题的组类

2,你必须有一个next 调用,它必须返回与你的组类神奇相关的“事物”之一。

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 部分中,您是否以某种方式明确声明/添加“关联类型”?即使没有明确要求你会如何明确地做到这一点?这种关联类型的业务到底是什么?

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

迅捷 而且,整个事情看起来不是很迅捷。仅仅为了添加迭代器输出而做所有这些似乎令人难以置信。在 Swift3 中,对于真正的课程,是否有更快捷的方式? (不是像“倒计时数字”这样愚蠢的例子。)

最后一个问题我很高兴地提到上面现在允许和.filter。事实上,我的例子是“完整的”吗——我现在可以用 DLList 做所有“迭代器”的事情吗,这在 Swift 中可以正常做——我可能是“忘记了一些特性”还是??让 DLList 成为一个非常好的迭代器还有更多工作要做吗?

【问题讨论】:

  • 值得注意的是,如果您不需要单独的迭代器类型,并且迭代的逻辑相对简单,您可以使用AnyIterator(我不知道这是否符合条件对你来说“更 Swifty”)——例如见 this gist.
  • @Hamish - 明白了,我想这是捷径,谢谢。很好地使用defer。多么完美的要点。

标签: iterator swift3 sequence


【解决方案1】:

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

例如IteratorProtocol 只有一个要求,即next() -> Element? 方法。如果您只是在 XCode 中 Cmd 并单击 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(例如,当您实现包装器时)。所以,分裂对我来说确实有意义。

【讨论】:

  • 天哪!你能帮我理解Element 是什么吗?这是在IteratorProtocol 中定义的吗?或者它是 Swift 中的标准类型,还是?谢谢!
  • @JoeBlow,Element 是与 IteratorProtocol 关联的类型(请参阅编辑)。
【解决方案2】:

这是我的小例子

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

【讨论】:

    猜你喜欢
    • 2017-02-09
    • 2019-08-15
    • 1970-01-01
    • 2018-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-17
    • 2017-02-21
    相关资源
    最近更新 更多