Как обрабатывать несколько общих протоколов в Swift? - PullRequest
0 голосов
/ 05 февраля 2019

Я пытаюсь использовать два общих протокола, которые связаны друг с другом как:

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 и этот Средний пост , но я не смог найти, где проблемаесть.

1 Ответ

0 голосов
/ 05 февраля 2019

Это происходит потому, что ваш 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 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>()
...