Избыточное дублирование объявлений typealiase при соответствии протоколу

#swift #collections #type-alias #swift-keypath

#swift #Коллекции #псевдоним типа #swift-ключевой путь

Вопрос:

 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)
    }
}
  

Это довольно полезный протокол, который помогает нам сократить шаблонный код при создании пользовательских коллекций.
Предположим, что наша структура оборачивает словарь. И мы хотим, чтобы это была коллекция, подобная этому словарю.
Мы должны указать ключевой путь к свойству dictionary и применить его к протоколу. И это работает!
Пример использования и мой вопрос:

 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>.Элемент’ (он же ‘(ключ: строка, значение: Int)’) эквивалентен

Комментарии:

1. Оказывается, вам не нужно переписывать оба псевдонима типа. Компилятору достаточно одного, чтобы разобраться. Но все же это странно.