Я хочу знать, почему мой SomeResourceRepository
по-прежнему является общим, хотя он определен только в одном случае, когда я устанавливаю ResourceType = SomeResource
, который форматирует XCode, как показано ниже с предложением where. Приведенный ниже код, который показывает точную настройку, которую я пытаюсь выполнить, написан на игровой площадке.
Я пытаюсь определить общий протокол для любого заданного ResourceType
, так что протокол ResourceTypeRepository
затем автоматически требуеттот же набор функций, без необходимости копировать-вставлять большую часть GenericRepository
только для того, чтобы вручную заполнить ResourceType для каждого создаваемого мной репозитория. Причина, по которой я нуждаюсь в этом как протоколе, заключается в том, что я хочу смоделировать это для целей тестирования позже. Поэтому я предоставлю реализацию указанного протокола где-то еще в реальном приложении.
Моя интерпретация приведенного ниже кода заключается в том, что он должен работать, потому что и SomeResourceLocalRepository
, и SomeResourceRemoteRepository
являются конкретными, как яисключил связанный тип, определив их "поверх" SomeResourceRepository
, который определяется только в том случае, если ResourceType == SomeResource
.
import Foundation
struct SomeResource: Identifiable {
let id: String
let name: String
}
struct WhateverResource: Identifiable {
let id: UUID
let count: UInt
}
protocol GenericRepository: class where ResourceType: Identifiable {
associatedtype ResourceType
func index() -> Array<ResourceType>
func show(id: ResourceType.ID) -> ResourceType?
func update(resource: ResourceType)
func delete(id: ResourceType.ID)
}
protocol SomeResourceRepository: GenericRepository where ResourceType == SomeResource {}
protocol SomeResourceLocalRepository: SomeResourceRepository {}
protocol SomeResourceRemoteRepository: SomeResourceRepository {}
class SomeResourceLocalRepositoryImplementation: SomeResourceLocalRepository {
func index() -> Array<SomeResource> {
return []
}
func show(id: String) -> SomeResource? {
return nil
}
func update(resource: SomeResource) {
}
func delete(id: String) {
}
}
class SomeResourceService {
let local: SomeResourceLocalRepository
init(local: SomeResourceLocalRepository) {
self.local = local
}
}
// Some Dip code somewhere
// container.register(.singleton) { SomeResourceLocalRepositoryImplementation() as SomeResourceLocalRepository }
Ошибки:
error: Generic Protocols.xcplaygroundpage:45:16: error: protocol 'SomeResourceLocalRepository' can only be used as a generic constraint because it has Self or associated type requirements
let local: SomeResourceLocalRepository
^
error: Generic Protocols.xcplaygroundpage:47:17: error: protocol 'SomeResourceLocalRepository' can only be used as a generic constraint because it has Self or associated type requirements
init(local: SomeResourceLocalRepository) {
Возможно, мне придетсянайти другой способ сделать это, но это утомительно и довольно раздражает, так как мы создадим много дублирующего кода, и когда мы решим изменить API наших репозиториев, нам придется вручную изменить его для всех протоколов, как мыне следуйте общему «родительскому» протоколу в этом обходном пути.
Я прочитал Как передать протокол со связанным типом в качестве параметра в Swift и связанный с этим вопрос, найденный в ответе наэтот вопрос, а также Specializing Generic Protocol и др.
Мне кажется, что это должно работать, но это не так. Конечной целью является конкретный протокол, который можно использовать для внедрения зависимостей, например, container.register(.singleton) { ProtocolImplementation() as Protocol }
согласно Dip - Простой контейнер внедрения зависимостей , НО без вставки копий, когда интерфейс протокола явно может быть сделан универсальным,как и выше.