Переопределение свойства с универсальным типом базового класса - PullRequest
0 голосов
/ 21 марта 2019

Вот что я хочу сделать:

protocol GenericFactory {
    associatedtype Input
    associatedtype Value
    func create(with input: Input) -> Value
}

class Base<Factory: GenericFactory> {
    var input: Factory.Input {
        preconditionFailure("To be overriden")
    }
}

protocol ValueProtocol {}
struct SomeInputImpl {}

protocol ValueFactory: GenericFactory where Input == SomeInputImpl, Value: ValueProtocol {}

class Child<Factory: ValueFactory>: Base<Factory> {
    override var input: Factory.Input {
        return SomeInputImpl()
    }
}

На линии swift override var input: Factory.Input { Я получаю ошибку Property 'input' with type 'SomeInputImpl' cannot override a property with type 'Factory.Input'.Я не понимаю причину этой ошибки, поскольку тип ввода описан в протоколе ValueFactory, но по ряду причин swift интерпретирует Factory.Input в base и Factory.input в Child как различные типы.Может кто-нибудь объяснить мне, что здесь не так?

Ответы [ 2 ]

2 голосов
/ 22 марта 2019

Просто чтобы завершить вопрос об этом в Swift 5, вот демонстрация, которая будет работать в Swift 5, но не в Swift 4.2, учитывая ваш пример кода.

struct Val: ValueProtocol {}

struct VF: ValueFactory {
    func create(with input: SomeInputImpl) -> Val {
        return Val()
    }
}

let child = Child<VF>()
child.input  // SomeInputImpl

Но вы быпочти наверняка лучше использовать функции, а не GenericFactory.Основная причина шаблона «Фабрика» заключается в работе с языками, в которых отсутствуют функции более высокого порядка и первоклассные типы, такими как Java до 8-й версии.В языках с функциями высшего порядка и первоклассными типами (такими как Swift) шаблон Factory обычно не нужен.Вы можете просто передать функцию (Input) -> Value напрямую.

В вашем примере не показан вызывающий объект, поэтому трудно точно определить, какое решение на основе функций будет работать лучше, но в большинстве случаев универсальные функции являютсяГораздо лучший подход, чем протоколы + связанный тип + обобщение + наследование.В частности, смешивание наследования классов с ассоциированными типами приводит к неправильным углам (поскольку ассоциированные типы и наследование классов представляют собой несколько ортогональные подходы к полиморфизму).

0 голосов
/ 21 марта 2019
protocol ValueFactory: GenericFactory where Input: SomeInputImpl, Value: ValueProtocol {}

Вход должен подтвердить SomeInputImpl.Так как SomeInputImpl является структурным типом, он не может быть унаследован.Таким образом, вы должны сделать это классом или протоколом

class SomeInputImpl {}

Затем вы можете переопределить входную переменную

class Child<Factory: ValueFactory>: Base<Factory> {
override var input: Factory.Input {
    return SomeInputImpl() as! Factory.Input
}

}

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