【问题标题】:Swift: Less code with nested enum cases conforming to equal protocolsSwift:具有符合相等协议的嵌套枚举案例的更少代码
【发布时间】:2019-04-25 12:32:02
【问题描述】:

我尝试在以下情况下编写更少的代码:

我有这个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)
}

示例用法

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
    }
})

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

一个小的改进是将 switch 语句隐藏在参数枚举的扩展中,并让它也符合 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 })

【问题讨论】:

    标签: swift generics enums


    【解决方案1】:

    由于您使用的是具有关联值的嵌套枚举,我真的没有办法避免在顶层Parameter 枚举上使用这个额外的开关。就我而言,Swift 并没有为我们提供一种处理案例的工具,即我们可以将所有具有“相同”关联值类型的案例转换为单个案例。您可以做的是重新考虑 Parameter 类型的存在,因为它似乎并没有真正有用,因为您仍然需要将其称为 Parameter&lt;BookParameters&gt;Parameter&lt;SomeOtherTypeThatConformsToQueryable&gt;

    我个人会跳过顶级枚举,直接将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
    

    【讨论】:

      【解决方案2】:

      如果不符合ParametersQueryable,您可以只在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
              }
          }
      }
      

      【讨论】:

      • 是的,但是我想知道是否有更简单的方法,因为在两种情况下,return 语句都是相同的。
      • 想不出来。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-23
      • 1970-01-01
      • 2018-05-14
      • 1970-01-01
      • 1970-01-01
      • 2018-12-14
      • 1970-01-01
      相关资源
      最近更新 更多