swift - 协议(protocol)只能用作通用约束,因为它具有 Self 或关联类型要求

标签 swift generics swift-protocols

继对我的 previous question 的回答之后, 我有 2 个协议(protocol)…

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
}

到目前为止一切都很好。

接下来我添加一个协议(protocol),Filterable,我希望任何符合 Filterable 的类型都能够返回参数,就像这样……

protocol Filterable {
    func parameters() -> QueryParameters
}

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

但我最终……

error: protocol 'QueryParameters' can only be used as a generic constraint because it has Self or associated type requirements

这似乎是一个非常简单的要求,但我花了 2 天的时间尝试所有我能想到的组合来让它工作。现在我终于认输了。

我需要做什么来解决这个问题?

最佳答案

正如我在评论中提到的。您的代码中缺少的是 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))
    }
} 

你已经完成了通用的东西。现在您可以创建符合您的协议(protocol)的不同模型对象

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)

您可以创建更多类型的查询参数和过滤器

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)

关于swift - 协议(protocol)只能用作通用约束,因为它具有 Self 或关联类型要求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50408628/

相关文章:

swift 2 : How to refer to a type of an element in default implementation of a function in a protocol

swift - 为什么是 'there cannot be more than one conformance, even with different conditional bounds' ?

swift - 如何让搜索栏在移动到另一个VC时立即消失

ios - Swift - 如何在 UIStackview 上设置点击事件

ios - 在 Swift 4 的 ContainerView 中查看

java - 对象化,Key<T> 可能吗?解决方法?

c# - 如何将 Task.WhenAll() 用于多个不同返回类型的列表?

swift - 实现接受并返回 Self 的协议(protocol)静态方法(快速)

swift - 在 Swift 中使用泛型实例化 Realm 对象

java - 了解内部泛型类