Ein neues Protokoll mit einer Standardimplementierung von makeIterator () in Sequence umsetzen

Ich habe ein (sehr einfaches) @ gemacBinaryTree Protokoll

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 }

}

Für ein grundlegendesiterative in-order Traversal, Ich machte einenBinaryTreeIterator (beachte, dass ich @ nicht implementieSequence Jetzt)

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]
    }

}

Das Implementieren eines binären Heaps in dieses Protokoll ist ebenfalls recht einfach:

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]
    }

}

So weit, ist es gut. Ich kann jetzt einen einfachen Haufen machen und durch seine Elemente iterieren:

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

Dies funktioniert, aber natürlich das Ziel der Implementierung vonmakeIterator() soll mit @ übereinstimmSequence. wenn ich jedoch @ erset

public protocol BinaryTree {

mi

public protocol BinaryTree: Sequence {

dann beschwert sich der Compiler, dassBinaryHeap implementiert @ nicSequence weil der zugehörige TypIterator konnte nicht gefolgert werden. Wenn ich das @ manuell eingeIterator tippe mit

extension BinaryHeap: BinaryTree {

    typealias Iterator = BinaryTreeIterator<BinaryHeap>

    ...

}

then der Compiler zeigt einen Fehler, dassIterator verweist sich kreisförmig auf sich selbst. Das könnte der Grund sein, warum dasIterator type konnte nicht abgeleitet werden.

Interessanterweise funktioniert es, wenn ich meine benutzerdefinierten @ WrBinaryTreeIterator in einem (nAnyIterator instance:

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

Apples eigeneIndexingIterator scheint ähnlich wie mein @ zu funktionierBinaryTreeIterator:

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

Von demQuellcod. Vielleicht liegt das Problem auch an der dort genannten Compiler-Einschränkung, aber ich weiß es nicht genau.

Gibt es eine Möglichkeit, sich anzupassenBinaryTree zuSequence ohne zu benutzenAnyIterator?

Antworten auf die Frage(4)

Ihre Antwort auf die Frage