我尝试使用类型删除来创建一个可以符合的Repository
协议(类似于Swift' s AnyCollection
)。此协议需要包装在类型擦除的类中,因为它包含PAT。
但是,由于此协议具有嵌套协议,该协议也具有PAT,因此有些复杂化。
Keyable
是一个提供密钥的东西(最终我也希望确保Hashable
......一次只做一件事。)Repository
是我的广义容器"协议AnyKeyable
Keyable
AnyRepository
Repository
我有一个 ALMOST 编译的游乐场代码段:
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()
声明,而不是AnyRepository
具体子类,但我不确定如何纠正这一点,为编译器提供更多的上下文。
有没有更好的方法来构建它以允许我完成这种模式?那也允许associatedtype
中的第一个Keyable
成为associatedtype KeyType where KeyType: Hashable
呢?
非常感谢任何帮助, 谢谢!
答案 0 :(得分:0)
正如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()
}
}