Протокол может использоваться только в качестве общего ограничения, потому что он имеет Self или требования к связанному типу. - PullRequest
0 голосов
/ 18 мая 2018

Исходя из ответа на мой предыдущий вопрос , у меня есть 2 протокола ...

protocol Filters: Encodable { 
}

protocol QueryParameters: Encodable {
    associatedtype T: Filters
    var page: Int { get }
    var filters: T { get }
}

, а затем для типа Transaction у меня есть ...

struct TransactionFilters: Filters {
    var isWithdrawal: Bool
}

struct TransactionParamters<T: Filters>: QueryParameters {
    var page: Int
    var filters: T
}

Пока все хорошо.

Далее я добавляю протокол, Filterable, и я бы хотел, чтобы любой тип, соответствующий Filterable, мог возвращать параметры, например ...

protocol Filterable {
    func parameters() -> QueryParameters
}

struct Transactions: Filterable {
    func parameters() -> QueryParameters {
        let transactionFilters = TransactionFilters(isWithdrawal: true)
        return TransactionParamters(page: 1, filters: transactionFilters)
    }
}

но я получаю ошибку…

: протокол 'QueryParameters' можно использовать только как общее ограничение, поскольку он имеет требования к Self или связанные с типами

Это кажется довольно простым требованием, но я потратил 2 дня, пробуя все возможные комбинации, чтобы заставить его работать.Теперь я наконец признаю поражение.

Что мне нужно сделать, чтобы решить эту проблему?

1 Ответ

0 голосов
/ 19 мая 2018

Как я уже упоминал в комментарии.В вашем коде отсутствует то, что associatedtype никогда не становится типом.Нигде в коде одного из ваших structs вы не назначаете тип для associatedtype.Если вам нужна универсальная filterable функциональность, вы можете сделать что-то вроде этого:

// Your generic Filters with required properties
protocol Filters: Encodable {
    var isWithdrawal: Bool { get }
    init(isWithdrawal: Bool)
}

// Your generic query parameters
protocol QueryParameters: Encodable {
    associatedtype F: Filters
    var page: Int { get }
    var filters: F { get }

    init(page: Int, filters: Filters)
}

// Filterable protocol will eventually accept any types conforming to Filters and QueryParameters
protocol Filterable {
    associatedtype F: Filters
    associatedtype P: QueryParameters

    func parameters() -> P
}

// This is your generic Transactions struct
// With this you will be able to pass other types that meet the constraints
struct Transactions<ParameterType: QueryParameters>: Filterable {
    typealias P = ParameterType
    typealias F = ParameterType.F

    func parameters() -> ParameterType {
        return P(page: 1, filters: F(isWithdrawal: true))
    }
} 

Вы закончили с универсальными вещами.Теперь вы можете создавать различные объекты модели, которые соответствуют вашим протоколам

struct TransactionFilters: Filters {
    private(set) var isWithdrawal: Bool // Conforming to filters
}

struct TransactionParameters<FilterType: Filters>: QueryParameters {
    // Telling what type is the object that conforms to Filters
    typealias F = FilterType
    var page: Int
    var filters: FilterType

    init(page: Int, filters: Filters) {
        self.page = page
        self.filters = filters as! F
    }
}

Создайте свой объект транзакций так:

let transactions = Transactions<TransactionParameters<TransactionFilters>>()
print(transactions.parameters().page)
print(transactions.parameters().filters.isWithdrawal)

Вы можете создавать больше типов QueryParameters и Filters

struct SomeOtherParameters<FilterType: Filters>: QueryParameters {
    // You can do custom stuff in your SomeOtherParameters struct
    // e.g. add an offset to page
    typealias F = FilterType
    var page: Int
    var filters: FilterType

    init(page: Int, filters: Filters) {
        self.page = page + 100
        self.filters = filters as! F
    }
}

// Your special filter that always returns false
struct SomeOtherFilters: Filters {
    init(isWithdrawal: Bool) {}

    var isWithdrawal: Bool {
        return false
    }
}

let transactionsWithDifferentFilters = Transactions<SomeOtherParameters<SomeOtherFilters>>()

// You can combine any types that conform to you declared protocols
let evenMoreTransactions = Transactions<SomeOtherParameters<TransactionFilters>>()
print(evenMoreTransactions.parameters().page)
...