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? {
// ...
}
}
而且,是的,一旦您实现了两者(Sequence
和 Iterator
,也就是说)您就可以做其他序列可以做的所有事情。这一切都归功于默认协议实现。
为了符合 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)")
}
我发现在 Swift 3 中找到使用 Sequence / IteratorProtocol 的“工作文档”非常困难。少数 tutorials/articles 似乎是针对较旧的 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
由于 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? {
// ...
}
}
而且,是的,一旦您实现了两者(Sequence
和 Iterator
,也就是说)您就可以做其他序列可以做的所有事情。这一切都归功于默认协议实现。
为了符合 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)")
}