【问题标题】:How to handle multiple generic protocols in Swift?如何在 Swift 中处理多个泛型协议?
【发布时间】:2019-02-05 14:24:12
【问题描述】:

我正在尝试使用两个相互关联的通用协议:

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 和这个 Medium post,但我找不到问题所在。

【问题讨论】:

  • 你为什么有associatedtype DataStoreType: DataStore where DataStoreType.DataType == DataType
  • 这个SO question 可能会对你有所帮助。

标签: swift generics protocols


【解决方案1】:

发生这种情况是因为您的 typealias for 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 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>()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多