【发布时间】:2019-10-14 14:02:06
【问题描述】:
我想知道为什么我的SomeResourceRepository 仍然是通用的,尽管它仅在一种情况下定义,即当我设置ResourceType = SomeResource 时,XCode 使用 where 子句将其格式化如下。下面的代码显示了我正在尝试实现的确切设置,写在 Playground 中。
我正在尝试为任何给定的ResourceType 定义一个通用协议,这样ResourceTypeRepository 协议就会自动需要相同的功能集,而无需复制粘贴大部分GenericRepository 来手动填写我创建的每个存储库的资源类型。我需要它作为协议的原因是因为我希望以后能够模拟它以进行测试。所以我会在实际应用程序的其他地方提供上述协议的实现。
我对下面代码的解释是它应该可以工作,因为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 时,我们将不得不手动更改它适用于所有协议,因为我们在此解决方法中不遵循通用的“父”协议。
我已阅读How to pass protocol with associated type as parameter in Swift 和在此问题的答案中找到的相关问题,以及Specializing Generic Protocol 和其他人。
我觉得这应该可行,但它没有。最终目标是一个可用于依赖注入的具体协议,例如container.register(.singleton) { ProtocolImplementation() as Protocol } 与 Dip - A simple Dependency Injection Container 相同,但是当协议的接口可以像上面那样明确地通用时,无需复制粘贴。
【问题讨论】:
-
我在 Swift 论坛上看到了这篇文章,这似乎是一个类似的问题。还没有答案。 forums.swift.org/t/constrained-pat-subprotocol/29767
-
@rraphael 谢谢,可以在那里注册并关注该主题。
标签: swift generics dependency-injection swift-protocols