Я пытаюсь использовать стирание типов для создания протокола Repository
, которому можно соответствовать (аналогично AnyCollection
Swift). Этот протокол необходимо обернуть в класс со стертым типом, поскольку он содержит PAT.
Однако, поскольку этот протокол имеет вложенный протокол, который также имеет PAT, это несколько усложняет ситуацию.
Keyable
- это то, что предоставляет ключ (который в конечном итоге я хотел бы убедиться, что он также являетсяHashable
... по одному за раз).Repository
- мой обобщенный "контейнерный" протоколAnyKeyable
обертка со стертым шрифтом дляKeyable
AnyRepository
обертка со стертым шрифтом дляRepository
У меня есть фрагмент игровой площадки, который ПОЧТИ компилируется:
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
?
Любая помощь приветствуется, спасибо!
get(id:)
в ластик типа? Ты точно хочешьfunc get(id: T.KeyType) throws -> T? { return try _get(id) }
? - person Hamish   schedule 13.12.2017Hashable
, который был закомментирован в моем посте. Я никогда не удалял его, и это значительно усложняло вещи больше, чем они должны были быть. - person Nick DiZazzo   schedule 14.12.2017