如何处理 Swift 中的多个泛型协议?
How to handle multiple generic protocols in Swift?
我正在尝试使用两个相互关联的通用协议:
protocol PersistableData {}
protocol DataStore: class {
associatedtype DataType: PersistableData
func save(data: DataType, with key: String)
func retreive(from key: String) -> DataType?
}
protocol PersistentDataModel {
// Swift infers that DataType: PersistableData as DataType == DataStoreType.DataType: PersistableData
// Setting it explicitly makes the compiler fail
associatedtype DataType
associatedtype DataStoreType: DataStore where DataStoreType.DataType == DataType
}
extension String: PersistableData {}
protocol StringDataStore: DataStore {
associatedtype DataType = String
}
class Test: PersistentDataModel {
typealias DataType = String
typealias DataStoreType = StringDataStore
}
但是 Xcode 无法编译说 Type 'Test' does not conform to protocol 'PersistentDataModel'
并建议 Possibly intended match 'DataStoreType' (aka 'StringDataStore') does not conform to 'DataStore'
而 StringDataStore
被定义为符合 DataStore
我已经阅读了一些关于通用协议的好资源,包括 SO and this Medium post,但我找不到问题出在哪里。
发生这种情况是因为您的 typealias
对于 associatedtype
应该是具体的,而不是抽象的。
因此,对于您的情况,StringDataStore
应该是 class
,而不是 protocol
。
protocol PersistableData {}
protocol DataStore: class {
associatedtype DataType: PersistableData
func save(data: DataType, with key: String)
func retreive(from key: String) -> DataType?
}
protocol PersistentDataModel {
// Swift infers that DataType: PersistableData as DataType == DataStoreType.DataType: PersistableData
// Setting it explicitly makes the compiler fail
associatedtype DataType
associatedtype DataStoreType: DataStore where DataStoreType.DataType == DataType
}
extension String: PersistableData {}
class StringDataStore: DataStore {
typealias DataType = String
func save(data: String, with key: String) {
//
}
func retreive(from key: String) -> String? {
return nil
}
}
class Test: PersistentDataModel {
typealias DataType = String
typealias DataStoreType = StringDataStore
}
但是,您可以继续使用协议并通过在 Test
class:
中使用额外的泛型条件来解决它
class Test<T: StringDataStore>: PersistentDataModel where T.DataType == String {
typealias DataStoreType = T
typealias DataType = T.DataType
}
使用这个你可以告诉编译器具体类型将被传递给 Test
其他地方。
像这样:
class ConcreteStringDataStore: StringDataStore {
func save(data: String, with key: String) {
//
}
func retreive(from key: String) -> String? {
return nil
}
}
let test = Test<ConcreteStringDataStore>()
我正在尝试使用两个相互关联的通用协议:
protocol PersistableData {}
protocol DataStore: class {
associatedtype DataType: PersistableData
func save(data: DataType, with key: String)
func retreive(from key: String) -> DataType?
}
protocol PersistentDataModel {
// Swift infers that DataType: PersistableData as DataType == DataStoreType.DataType: PersistableData
// Setting it explicitly makes the compiler fail
associatedtype DataType
associatedtype DataStoreType: DataStore where DataStoreType.DataType == DataType
}
extension String: PersistableData {}
protocol StringDataStore: DataStore {
associatedtype DataType = String
}
class Test: PersistentDataModel {
typealias DataType = String
typealias DataStoreType = StringDataStore
}
但是 Xcode 无法编译说 Type 'Test' does not conform to protocol 'PersistentDataModel'
并建议 Possibly intended match 'DataStoreType' (aka 'StringDataStore') does not conform to 'DataStore'
而 StringDataStore
被定义为符合 DataStore
我已经阅读了一些关于通用协议的好资源,包括 SO and this Medium post,但我找不到问题出在哪里。
发生这种情况是因为您的 typealias
对于 associatedtype
应该是具体的,而不是抽象的。
因此,对于您的情况,StringDataStore
应该是 class
,而不是 protocol
。
protocol PersistableData {}
protocol DataStore: class {
associatedtype DataType: PersistableData
func save(data: DataType, with key: String)
func retreive(from key: String) -> DataType?
}
protocol PersistentDataModel {
// Swift infers that DataType: PersistableData as DataType == DataStoreType.DataType: PersistableData
// Setting it explicitly makes the compiler fail
associatedtype DataType
associatedtype DataStoreType: DataStore where DataStoreType.DataType == DataType
}
extension String: PersistableData {}
class StringDataStore: DataStore {
typealias DataType = String
func save(data: String, with key: String) {
//
}
func retreive(from key: String) -> String? {
return nil
}
}
class Test: PersistentDataModel {
typealias DataType = String
typealias DataStoreType = StringDataStore
}
但是,您可以继续使用协议并通过在 Test
class:
class Test<T: StringDataStore>: PersistentDataModel where T.DataType == String {
typealias DataStoreType = T
typealias DataType = T.DataType
}
使用这个你可以告诉编译器具体类型将被传递给 Test
其他地方。
像这样:
class ConcreteStringDataStore: StringDataStore {
func save(data: String, with key: String) {
//
}
func retreive(from key: String) -> String? {
return nil
}
}
let test = Test<ConcreteStringDataStore>()