Соответствие стандартному методу протокола, возвращающему PAT - PullRequest
0 голосов
/ 04 декабря 2018

Я хотел бы объявить общие протоколы, подобные следующим:

protocol Factory {
    func createWidget<T, TWidget>(_ t: T) -> TWidget 
    where TWidget: Widget, TWidget.T == T
}

protocol Widget {
    associatedtype T
    func get() -> T
}

Я надеюсь, что смогу реализовать конкретные варианты Factory, возвращая свои собственные конкретные и непрозрачные Widget сскрытая реализация.

Вот пример реализации, которую не удается построить:

struct ConcreteFactory: Factory {
    func createWidget<T, TWidget>(_ t: T) -> TWidget 
    where TWidget: Widget, TWidget.T == T {
        // This line has an error…
        return ConcreteWidget(widgetValue: t)
    }
}

struct ConcreteWidget<T>: Widget {
    let widgetValue: T

    init(widgetValue: T) {
        self.widgetValue = widgetValue
    }

    func get() -> T {
        return widgetValue
    }
}

Однако это не компилируется.

В указанной строке компилятор Swift выдает ошибку «Невозможно преобразовать возвращаемое выражение типа 'ConcreteWidget' в возвращаемый тип 'TWidget'".

Я также пытался заставить ConcreteFactory вернуть a ConcreteWidget, но тогда ошибка в том, что ConcreteFactory не соответствует Factory.

1 Ответ

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

Это не может работать.Когда вы вызываете ваш createWidget метод, вы указываете два типа T и TWidget.

struct MyWidget: Widget { 
   func get() -> Int { ... }
}

let widget: MyWidget = factory.createWidget(12)

. В этом примере TWidget равно MyWidget, а T равноInt.И это прекрасно показывает, почему ваш подход не работает.Вы не можете присвоить ConcreteWidget<Int> переменной типа MyWidget.

. Вам нужен стирающий тип для ваших виджетов.В настоящее время вы должны написать это самостоятельно, но в будущем, мы надеемся, компилятор автоматически сгенерирует их при необходимости.

struct AnyWidget<T>: Widget {
    private let _get: () -> T

    init<Other: Widget>(_ other: Other) where Other.T == T {
        _get = other.get
    }

    func get() -> T {
        return _get()
    }
}

Это позволит вам написать свой заводской протокол и реализацию:

protocol Factory {
    func createWidget<T>(_ t: T) -> AnyWidget<T>
}

struct ConcreteFactory: Factory {
    func createWidget<T>(_ t: T) -> AnyWidget<T> {
            return AnyWidget(ConcreteWidget(widgetValue: t))
    }
}
...