通用类型在不透明类型的帮助下符合 Sequence:一些 IteratorProtocol
Generic type conforms to Sequence with help of opaque type: some IteratorProtocol
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, +)
导致编译错误:
Cannot convert value of type '(Int) -> Int' to expected argument type
'(Int, (some IteratorProtocol).Element) throws -> 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([=11=]) }
}
mutating func next() -> Node.T? {
guard let current = queue.pop() else { return nil }
queue.push(contentsOf: current.children)
return current.value
}
}
发生这种情况是因为当前 Swift (5.2) 无法为不透明的 return 值指定关联类型。因此,some IteratorProtocol
不足以让编译器确定 next()
方法 return.
应该使用什么样的值
如果您想实际使用序列,语言的这种限制会强制您显式声明迭代器类型。
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, +)
导致编译错误:
Cannot convert value of type '(Int) -> Int' to expected argument type '(Int, (some IteratorProtocol).Element) throws -> 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([=11=]) }
}
mutating func next() -> Node.T? {
guard let current = queue.pop() else { return nil }
queue.push(contentsOf: current.children)
return current.value
}
}
发生这种情况是因为当前 Swift (5.2) 无法为不透明的 return 值指定关联类型。因此,some IteratorProtocol
不足以让编译器确定 next()
方法 return.
如果您想实际使用序列,语言的这种限制会强制您显式声明迭代器类型。