Swift:使用符合相同协议的嵌套枚举案例的代码较少

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift:使用符合相同协议的嵌套枚举案例的代码较少相关的知识,希望对你有一定的参考价值。

我尝试在以下场景中编写更少的代码:

我有这个Queryable协议和Parameter枚举:

protocol Queryable {
    var urlQuery: URLQueryItem { get }
}

enum PaginationParameter: Queryable {
    case page(Int)
    case pageSize(Int)

    var queryItem: URLQueryItem {
        switch self {
        case .page(let page):
            return URLQueryItem(name: "page", value: page.description)
        case .pageSize(let pageSize):
            return URLQueryItem(name: "page_size", value: pageSize.description)
        }
    }
}

并且枚举提供了一些默认情况和一些由泛型类型定义的特定情况:

enum Parameter<P: Queryable> {
    case pagination(PaginationParameter)
    case specific(P)
}

Example Usage

enum BookParameters: Queryable {
    case search(String)
    case id(Int)

    var urlQuery: URLQueryItem {
        switch self {
        case .search(let string):
            return URLQueryItem(name: "search", value: string)
        case .id(let id):
            return URLQueryItem(name: "id", value: id.description)
        }
    }
}

let parameters: [Parameter<BookParameters>] = [
    .pagination(.pageSize(10)),
    .specific(.id(123))
]

现在我需要通过.pagination.specific案例获取url查询项。

let queryItems = parameters.map({
    switch $0 {
    case .pagination(let param):
        return param.queryItem
    case .specific(let param):
        return param.queryItem
    }
})

有一种方法可以处理嵌套的情况,因为它们符合相同的协议。这不起作用,因为我必须通过父案例转到嵌套案例:

一个小的改进是将switch语句埋在Parameters枚举的扩展中,并让它符合Queryable协议:

extension Parameters: Queryable {

    let queryItem: URLQueryItem {
        switch self {
        case .pagination(let param):
            return param.queryItem
        case .specific(let param):
            return param.queryItem
        }
    }
}

这导致一个班轮,但我只是把我的问题转移到另一个地方。

let queryItems = parameters.map({ $0.queryItem })
答案

由于您使用的是带有关联值的嵌套枚举,我真的没有办法避免在顶级Parameter枚举上使用这个额外的开关。就我而言,Swift没有为我们提供一个工具来处理案例,我们可以将所有案例与“相同”的相关值类型一起投射到一个案例中。你可以做的是重新考虑Parameter类型的存在,因为它似乎并没有真正有用,因为你仍然需要将它称为Parameter<BookParameters>Parameter<SomeOtherTypeThatConformsToQueryable>

我个人会跳过顶级枚举,并直接将parameters属性类型称为[Queryable]

var parameters: [Queryable] = [
    PaginationParameter.pageSize(10),
    BookParameters.id(123)
]

使事情更简单,更容易推理。此外,现在有一种方法可以添加其他类型的其他情况,而初始解决方案则无法实现。

enum SomeOtherTypeThatConformsToQueryable: Queryable {
    case aVeryNiceCase(Int)
}

parameters.append(SomeOtherTypeThatConformsToQueryable.aVeryNiceCase(0))
// Appending this to array of type `[Parameter<BookParameters>]`, would not be
// possible without explicitly adding new case to the `Parameter` enumeration

此外,如果你发现自己经常调用map { $0.queryItem },你可以提供Array的扩展,其中ElementQueryable的类型

extension Array where Element==Queryable {
    var queryItems: [URLQueryItem] { return map { $0.queryItem } }
}

// And now you can simply call
let queryItems = parameters.queryItems
另一答案

如果没有使Parameters符合Queryable,你可以在Parameters中引入一个变量来获得queryItem,因为两种情况都接受一种已经符合Queryable的类型,

enum Parameter<P: Queryable> {
    case pagination(PaginationParameter)
    case specific(P)

    var urlQuery: URLQueryItem {
        switch self {
        case .pagination(let param):
            return param.urlQuery
        case .specific(let param):
            return param.urlQuery
        }
    }
}

以上是关于Swift:使用符合相同协议的嵌套枚举案例的代码较少的主要内容,如果未能解决你的问题,请参考以下文章

协议类型“Encodable”的值不能符合“Encodable”;只有结构/枚举/类类型可以符合协议

在 Swift 的嵌套循环中从特定索引枚举字符串

Swift 中的可散列枚举

Swift中扩展的使用

如何获得 Swift 枚举的计数?

swift2.0学习之拓展