Невозможно использовать протокол для определения общих инициализаторов - PullRequest
1 голос
/ 27 апреля 2020

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

Cannot convert value of type 'Model' (generic parameter of generic class 'Store') to expected argument type 'ViewModel.Model' (associated type of protocol 'StoreViewModel')

Я использую следующий упрощенный код:

protocol StoreViewModel {
    associatedtype Model

    init(model: Model)
}

class Store<Model, ViewModel: StoreViewModel> {
    var models = [Model]()
    var results = [ViewModel]()

    func update() {
        results = models.map {
            ViewModel(model: $0)
            // Cannot convert value of type 'Model' (generic parameter of generic class 'Store') to expected argument type 'ViewModel.Model' (associated type of protocol 'StoreViewModel')
        }
    }
}

class Foo: NSManagedObject {}

class FooViewModel: StoreViewModel {
    var model: Foo
    required init(model: Foo) {
        self.model = model
    }
}

let store = Store<Foo, FooViewModel>()

Я уже читал об удалении типа, но мне интересно, что нет более простого решения этой проблемы.

1 Ответ

3 голосов
/ 27 апреля 2020

Как таковой, ваш текущий код допускает такие вещи, как:

let store = Store<Int, FooViewModel>()

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

Давайте наложим ограничение на:

class Store<Model, ViewModel: StoreViewModel> where Model == ViewModel.Model {

Теперь мы видим, что нет смысла иметь два обобщенных c параметра! Зачем использовать Model, когда мы можем просто использовать ViewModel.Model?

class Store<ViewModel: StoreViewModel> {
    var models = [ViewModel.Model]()

или, если вы ненавидите длинные имена типов, используйте typealias:

typealias Model = ViewModel.Model
var models = [Model]()
...