Превратите «протокол со связанным типом» в обычный протокол, указав тип - PullRequest
0 голосов
/ 19 декабря 2018

У меня есть следующий протокол:

protocol PieceViewGateway {
    subscript(_ identifier: PieceIdentifier) -> UIView {get}
}

Я использую это во многих местах таким образом:

struct SomeKindOfThing {
  let viewGateway: PieceViewGateway
}

Это все хорошо и очень приятно.

Вот один пример конкретной реализации протокола (есть и другие реализации):

struct ViewDictionaryPieceViewGateway: PieceViewGateway {
    let viewDictionary: [PieceIdentifier: UIView]

    subscript(identifier: PieceIdentifier) -> UIView {
        guard let item = viewDictionary[identifier] else { 
          fatalError("Gateway has no value for key: \(identifier)") 
        }

        return item
    }
}

У меня есть несколько таких протоколов.Другой - PieceValueGateway, который возвращает Int вместо UIView.

Мне бы не хотелось реализовывать что-то вроде ViewDictionaryPieceViewGateway для различных «аспектов», для которых мне нужны шлюзы.

Я пытался добиться этого, определяя протокол с помощьюсвязанный тип для шлюзов модели:

protocol PieceAspectGateway {
    associatedtype Aspect
    subscript(_ identifier: PieceIdentifier) -> Aspect {get}

}

Я бы тогда согласился PieceViewGateway с этим:

protocol PieceViewGateway: PieceAspectGateway {
    subscript(_ identifier: PieceIdentifier) -> UIView {get}
}

Однако, это дает много ошибок компиляции, которые:

Протокол 'PieceViewGateway' может использоваться только в качестве общего ограничения, поскольку он имеет собственные требования или требования к связанным типам

Об ошибках сообщается в коде , который был в порядке доЯ добавил соответствие PieceViewGateway: PieceAspectGateway.Например, SomeKindOfThing, объявляющий это, имеет let viewGateway: PieceViewGateway.

Я также пытался соответствовать следующим образом:

protocol PieceViewGateway: PieceAspectGateway where Aspect == UIView {
    subscript(_ identifier: PuzzlePieceIdentifier) -> UIView {get}
}

И так:

protocol PieceViewGateway: PieceAspectGateway {
    typealias Aspect = UIView
    subscript(_ identifier: PuzzlePieceIdentifier) -> UIView {get}
}

… но все эти варианты дают одинаковую ошибку при использовании PieceViewGatewayв качестве протокола.

Есть ли способ достичь этого?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

То, что вы хотите выполнить, довольно просто:

protocol PieceAspectGateway {
    associatedtype Aspect
    subscript(_ identifier: PieceIdentifier) -> Aspect {get}
}

, поэтому у вас есть этот протокол.Если вы хотите наследовать от него и использовать более конкретный тип, вы можете использовать общее ограничение:

protocol IntPieceAspectGateway: PieceAspectGateway where Aspect == Int {
    ...
}
0 голосов
/ 19 декабря 2018

Вы можете использовать protocol с associatedtype и ластиком для создания любого типа Gateway.Пожалуйста, смотрите ниже,

protocol PieceAspectGateway {
    associatedtype Aspect
    subscript(_ identifier: PieceIdentifier) -> Aspect {get}

}

struct AnyGateway<T>: PieceAspectGateway {
    let dictionary: [PieceIdentifier: T]

    subscript(identifier: PieceIdentifier) -> T {
        guard let item = dictionary[identifier] else {
            fatalError("Gateway has no value for key: \(identifier)")
        }
        return item
    }
}

Использование

let viewGateway: AnyGateway<UIView>
let viewGateways: [AnyGateway<UIView>] = []

let intGateway: AnyGateway<Int>
let intGateways: [AnyGateway<Int>] = []

let stringGateway: AnyGateway<String>
let stringGateways: [AnyGateway<String>] = []
...