Соответствие нового протокола Sequence с реализацией makeIterator() по умолчанию
Я сделал (очень простой) 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 }
}
Для базового итеративного обхода в порядке я сделал 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 {
...
}
Из исходного кода. Может быть, проблема, с которой я сталкиваюсь, может быть также из-за упомянутых там ограничений компилятора, но я точно не знаю.
Есть ли способ соответствовать BinaryTree
в Sequence
без использования AnyIterator
?
2 ответа
Очевидно, это была ошибка Swift: мой код хорошо компилируется с помощью Swift 3.1.
Это самое дальнее, что я мог взять. Теперь компилятор все равно будет жаловаться на кучу, не содержащую какого-либо члена makeIterator (который, как я думал, был включен по умолчанию, как только кто-то соответствует последовательности - неправильно получается, что для реализации по умолчанию нужно соответствовать Sequence и IteratorProtocol) и иметь следующий - но как только вы добавите эти методы, его плавное плавание.
Так что makeIterator + следующий способ сделать счастливым компилятор 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: " ")
}