问题描述
protocol TreeNode: AnyObject {
associatedtype T
var value: T { get set }
var children: [Self] { get }
init(_ value: T)
}
protocol Tree: Sequence {
associatedtype Node: TreeNode
var root: Node? { get set }
}
extension Tree {
typealias T = Node.T
func makeIterator() -> some IteratorProtocol {
BFSIterator(startFrom: root)
}
}
这可以编译并且看起来很有希望。
但是随后突然在单元测试行let sum = tree.reduce(0,+)
中导致编译错误:
无法将类型'(Int)-> Int'的值转换为预期的参数类型 '((Int,(某些IteratorProtocol).Element)抛出-> Int'
为什么编译器无法弄清楚(some IteratorProtocol).Element
确实是Int
?以及如何帮助呢?
请注意,如果我使用“旧方法”(没有不透明类型): func makeIterator()-> BFSIterator { 一切都能编译并完美运行。
更新:
struct BFSIterator<Node: TreeNode>: IteratorProtocol {
private var queue: Queue<Node> = []
init(startFrom root: Node?) {
root.map { queue.push($0) }
}
mutating func next() -> Node.T? {
guard let current = queue.pop() else { return nil }
queue.push(contentsOf: current.children)
return current.value
}
}
解决方法
之所以发生这种情况,是因为当前的Swift(5.2)中无法为不透明的返回值指定关联的类型。因此,some IteratorProtocol
不足以使编译器确定next()
方法应返回哪种值。
语言的这种局限性迫使您在实际使用序列时明确声明迭代器类型。