我正在尝试使用类型删除来创建 Repository
可以遵循的协议(protocol)(类似于 Swift 的 AnyCollection
)。该协议(protocol)需要包装在类型删除的类中,因为它包含 PAT。
但是,由于该协议(protocol)有一个嵌套协议(protocol),该协议(protocol)也有一个 PAT,所以它使事情变得有些复杂。
-
Keyable
是提供 key 的东西(最终我想确保也是Hashable
...一次一件事)。 -
Repository
是我的广义“容器”协议(protocol) -
AnyKeyable
Keyable
的类型删除包装 -
AnyRepository
Repository
的类型删除包装
我有一个几乎编译的 Playground 片段:
protocol Keyable {
associatedtype KeyType// where KeyType: Hashable
func key() -> KeyType
}
protocol Repository {
associatedtype DataType: Keyable
func all() -> [DataType]
func get(id: DataType.KeyType) throws -> DataType?
func create(object: DataType) throws -> Bool
func update(object: DataType) throws -> Bool
func delete(object: DataType) throws -> Bool
func clear() -> Bool
}
final class AnyKeyable<T>: Keyable {
private let _key: () -> T
init<U: Keyable>(_ keyable: U) where U.KeyType == T {
_key = keyable.key
}
public func key() -> T {
return _key()
}
}
final class AnyRepository<T: Keyable>: Repository {
private let _all: () -> [T]
private let _get: (_ id: T.KeyType) throws -> T?
private let _create: (_ object: T) throws -> Bool
private let _update: (_ object: T) throws -> Bool
private let _delete: (_ object: T) throws -> Bool
private let _clear: () -> Bool
init<U: Repository>(_ repository: U) where U.DataType == T {
_get = repository.get
_create = repository.create
_delete = repository.delete
_update = repository.update
_clear = repository.clear
_all = repository.all
}
func all() -> [T] {
return _all()
}
func get<K: Keyable>(id: K.KeyType) throws -> T? where T.KeyType: Keyable, T.KeyType == K.KeyType {
let anyKeyable = AnyKeyable(id)
return try _get(anyKeyable)
}
func create(object: T) throws -> Bool {
return try _create(object)
}
func update(object: T) throws -> Bool {
return try _update(object)
}
func delete(object: T) throws -> Bool {
return try _delete(object)
}
func clear() -> Bool {
return _clear()
}
}
final class Contact {
var name: String = ""
var email: String = ""
}
extension Contact: Keyable {
public typealias KeyType = String
public func key() -> String {
return "im the key"
}
}
// Just a dummy class to see
final class ContactRepository: Repository {
typealias DataType = Contact
private var someContacts: [Contact] = []
func all() -> [Contact] {
return someContacts
}
func clear() -> Bool {
someContacts.removeAll()
return someContacts.count == 0
}
func get(id: Contact.KeyType) throws -> Contact? {
return nil
}
func update(object: Contact) throws -> Bool {
return false
}
func create(object: Contact) throws -> Bool {
return false
}
func delete(object: Contact) throws -> Bool {
return false
}
}
// Testing
let i = AnyRepository<Contact>(ContactRepository())
i.all()
i.clear()
问题是 Swift 编译器提示我没有使用 K
在 get<K: Keyable>(id: K.KeyType)
的方法签名中......但在我看来,我确实是。
我的想法是编译器因为DataType.KeyType
而提示声明get()
在协议(protocol)中,而不是在 AnyRepository
中具体子类,但我不确定如何纠正这个问题以为编译器提供更多上下文。
有没有更好的方法来构建它以允许我完成这个模式?也允许第一个associatedtype
怎么样?在Keyable
成为associatedtype KeyType where KeyType: Hashable
?
非常感谢任何帮助, 谢谢!
最佳答案
正如 Hamish 指出的那样,没有必要引入另一个泛型 K
。这让事情变得复杂了。清理完所有内容后,现在无需 AnyKeyable
类的复杂化即可工作:
public protocol Keyable {
associatedtype KeyType where KeyType: Hashable
func key() -> KeyType
}
public protocol Repository {
associatedtype DataType: Keyable
func all() -> [DataType]
func get(id: DataType.KeyType) throws -> DataType?
func create(object: DataType) throws
func create(objects: [DataType]) throws
func update(object: DataType) throws
func delete(object: DataType) throws
func delete(objects: [DataType]) throws
func clear()
}
public class AnyRepository<T: Keyable>: Repository {
private let _all: () -> [T]
private let _get: (_ id: T.KeyType) throws -> T?
private let _create: (_ object: T) throws -> Void
private let _createAll: (_ objects: [T]) throws -> Void
private let _update: (_ object: T) throws -> Void
private let _delete: (_ object: T) throws -> Void
private let _deleteAll: (_ objects: [T]) throws -> Void
private let _clear: () -> Void
public init<R: Repository>(_ repository: R) where R.DataType == T {
_get = repository.get
_create = repository.create
_createAll = repository.create
_delete = repository.delete
_deleteAll = repository.delete
_update = repository.update
_clear = repository.clear
_all = repository.all
}
public func all() -> [T] {
return _all()
}
public func get(id: T.KeyType) throws -> T? {
return try _get(id)
}
public func create(object: T) throws {
return try _create(object)
}
public func create(objects: [T]) throws {
return try _createAll(objects)
}
public func update(object: T) throws {
return try _update(object)
}
public func delete(object: T) throws {
return try _delete(object)
}
public func delete(objects: [T]) throws {
return try _deleteAll(objects)
}
public func clear() {
return _clear()
}
}
关于swift - 如何创建符合具有嵌套 PAT 的协议(protocol)的类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47799938/