3
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)')是等价的

4

0 回答 0