使用默认的makeIterator()实现将新协议与Sequence一致

时间:2016-06-30 10:35:29

标签: swift swift3 swift-protocols

我做了一个(非常基本的)BinaryTree协议:

public enum BinaryTreeChildSide {
    case left, right
}

public protocol BinaryTree {

    associatedtype Element
    associatedtype Index

    func child(of index: Index, side: BinaryTreeChildSide) -> Index?
    var rootIndex: Index? { get }
    subscript(position: Index) -> Element { get }

}

对于基本的iterative in-order traversal,我制作了BinaryTreeIterator(请注意,我还没有实现Sequence):

public extension BinaryTree {

    func makeIterator() -> BinaryTreeIterator<Self> {
        return BinaryTreeIterator(self)
    }

}

public struct BinaryTreeIterator<Tree: BinaryTree>: IteratorProtocol {

    private let tree: Tree
    private var stack: [Tree.Index]
    private var index: Tree.Index?

    private init(_ tree: Tree) {
        self.tree = tree
        stack = []
        index = tree.rootIndex
    }

    public mutating func next() -> Tree.Element? {
        while let theIndex = index {
            stack.append(theIndex)
            index = tree.child(of: theIndex, side: .left)
        }

        guard let currentIndex = stack.popLast() else { return nil }
        defer { index = tree.child(of: currentIndex, side: .right) }

        return tree[currentIndex]
    }

}

为此协议实现二进制堆也非常简单:

public struct BinaryHeap<Element> {

    private var elements: [Element]

    public init(_ elements: [Element]) {
        self.elements = elements
    }

}

extension BinaryHeap: BinaryTree {

    private func safeIndexOrNil(_ index: Int) -> Int? {
        return elements.indices.contains(index) ? index : nil
    }

    public func child(of index: Int, side: BinaryTreeChildSide) -> Int? {
        switch side {
        case .left: return safeIndexOrNil(index * 2 + 1)
        case .right: return safeIndexOrNil(index * 2 + 2)
        }
    }

    public var rootIndex: Int? { return safeIndexOrNil(0) }

    public subscript(position: Int) -> Element {
        return elements[position]
    }

}

到目前为止,这么好。我现在可以创建一个简单的堆并遍历其元素:

let heap = BinaryHeap([4, 2, 6, 1, 3, 5, 7])
var iterator = heap.makeIterator()

while let next = iterator.next() {
    print(next, terminator: " ")
}
// 1 2 3 4 5 6 7

这很有效,但实现makeIterator()的目标当然是符合Sequence。但是,如果我更换

public protocol BinaryTree {

public protocol BinaryTree: Sequence {

然后编译器抱怨BinaryHeap没有实现Sequence,因为无法推断出关联的类型Iterator。如果我使用

手动指定Iterator类型
extension BinaryHeap: BinaryTree {

    typealias Iterator = BinaryTreeIterator<BinaryHeap>

    ...

}

然后编译器显示Iterator循环引用自身的错误。这可能就是无法推断出Iterator类型的原因。

有趣的是,如果我将自定义BinaryTreeIterator包装在AnyIterator实例中,它就有效:

public extension BinaryTree {

    func makeIterator() -> AnyIterator<Element> {
        return AnyIterator(BinaryTreeIterator(self))
    }

}

let heap = BinaryHeap([4, 2, 6, 1, 3, 5, 7])

for number in heap {
    print(number, terminator: " ")
}
// 1 2 3 4 5 6 7

Apple自己的IndexingIterator似乎与BinaryTreeIterator的工作方式类似:

public struct IndexingIterator<
    Elements : IndexableBase
    // FIXME(compiler limitation):
    // Elements : Collection
> : IteratorProtocol, Sequence {
    ...
}

来自source code。也许我面临的问题也可能是因为那里提到的编译器限制,但我不确定。

有没有办法在不使用BinaryTree的情况下使Sequence符合AnyIterator

2 个答案:

答案 0 :(得分:0)

这是我能拿到的最远的。现在编译器仍会抱怨堆不包含任何makeIterator成员 (我认为默认包含一旦有人符合序列错误的结果,必须符合Sequence IteratorProtocol的默认实现)并且有一个下一个 - 但是一旦你添加了这些方法顺风顺水。

所以makeIterator + next方法让Mr / Mrs / Preferred Gender Pronoun编译器感到高兴。

public enum BinaryTreeChildSide {
    case left, right
}

public struct BinaryTreeIterator<Tree: BinaryTree>: Sequence, IteratorProtocol {

    private let tree: Tree
    private var stack: [Tree.Index]
    private var index: Tree.Index?

    private init(_ tree: Tree) {
        self.tree = tree
        stack = []
        index = tree.rootIndex
    }

    public mutating func next() -> Tree.Element? {
        while let theIndex = index {
            stack.append(theIndex)
            index = tree.child(of: theIndex, side: .left)
        }

        guard let currentIndex = stack.popLast() else { return nil }
        defer { index = tree.child(of: currentIndex, side: .right) }

        return tree[currentIndex]
    }

}


public protocol BinaryTree: Sequence {

    associatedtype Element
    associatedtype Index

    func child(of index: Index, side: BinaryTreeChildSide) -> Index?
    var rootIndex: Index? { get }
    subscript(position: Index) -> Element { get }

}



extension BinaryTree {

    func makeIterator() -> BinaryTreeIterator<Self> {
        return BinaryTreeIterator(self)
    }

}

extension BinaryHeap {


    private func safeIndexOrNil(_ index: Int) -> Int? {
        return elements.indices.contains(index) ? index : nil
    }

    public func child(of index: Int, side: BinaryTreeChildSide) -> Int? {
        switch side {
        case .left: return safeIndexOrNil(index * 2 + 1)
        case .right: return safeIndexOrNil(index * 2 + 2)
        }
    }

    public var rootIndex: Int? { return safeIndexOrNil(0) }

    public subscript(position: Int) -> Element {
        return elements[position]
    }

}

public struct BinaryHeap<Element> {

    private var elements: [Element]


    public init(_ elements: [Element]) {
        self.elements = elements
    }

}

let heap = BinaryHeap([4, 2, 6, 1, 3, 5, 7])
var iterator = heap.makeIterator()

while let next = iterator.next() {
    print(next, terminator: " ")
}

答案 1 :(得分:-1)

显然这是一个Swift错误:我的代码使用Swift 3.1编译得很好。