protocol PathCollection: Collection where Element == Target.Element, Index == Target.Index {
associatedtype Target: Collection
static var reference: KeyPath<Self, Target> { get }
}
extension PathCollection {
private var target: Target { self[keyPath: Self.reference] }
var startIndex: Index { target.startIndex }
var endIndex: Index { target.endIndex }
subscript(index: Index) -> Element {
get { target[index] }
}
func index(after i: Index) -> Index {
target.index(after: i)
}
}
这是一个非常有用的协议,可以帮助我们在创建自定义集合时减少样板代码。
假设我们的结构包装了一个字典。我们希望它像那本字典一样成为一个集合。
我们应该为字典属性提供 keyPath 并应用于协议。它有效!
用法示例和我的问题:
protocol Graph: PathCollection where Target == [String: Int] {
var storage: [String: Int] { get set }
}
extension Graph {
static var reference: KeyPath<Self, [String: Int]> { \.storage }
}
struct UndirectedGraph: Graph {
typealias Element = Dictionary<String, Int>.Element // Why should we again declare this typealias!?
typealias Index = Dictionary<String, Int>.Index // Why should we again declare this typealias!?
var storage: [String: Int]
}
它完美地工作。但是我们为什么要重新声明元素和索引类型别名!?在这篇文章的第一行代码中,我们明确定义了元素和索引:
protocol PathCollection: Collection where Element == Target.Element, Index == Target.Index {
接着:
protocol Graph: PathCollection where Target == [String: Int] {
如果我删除该重新声明,我会收到一个我不明白的编译错误:
'PathCollection' 要求类型 'Slice' 和 'Dictionary<String, Int>.Element'(又名 '(key: String, value: Int)')是等价的