美文网首页iOS技术点
挑战:筛选关联值枚举数组

挑战:筛选关联值枚举数组

作者: 梁杰_numbbbbb | 来源:发表于2017-02-09 21:09 被阅读26次

作者:Erica Sadun,原文链接,原文日期:2017-01-31
译者:星夜暮晨;校对:Crystal Sun;定稿:CMB

本挑战由 Mike Ash 提供,如下所示,假设有这样一个枚举:

enum Enum {
    case foo(Int)
    case bar(String)
    case qux(Int)
}

这些枚举还组成了的一个数组:

let items: [Enum] = [.foo(1), .bar("hi"), .foo(2)]

需要对数组进行筛选 (filter),挑选并创建只包含某种枚举值 (case) 的新数组。麻烦的是,Swift 没有一种类似 ==_= 的操作符,可以让我们忽略枚举的关联值:

// 不起作用
let filtered = items.filter({ $0 == .foo })

那么应该怎么办呢?

第一次尝试

这是第一次尝试。代码尽管很丑,但是能用:

let filtered = items.filter({ 
    switch $0 { case .foo: return true; default: return false } })

Evan Dekhayser 更偏好于 if-case

let filtered = items.filter({ 
    if case .foo = $0 { return true }; return false })

当然,这里也可以使用 guard

let filteredy = items.filter({ 
    guard case .foo = $0 else { return false }; return true })

第二次尝试

尽管同样丑陋,由于节省了几个字符,这段代码看起来要稍微简短一些。不过代码所需的执行步骤远比第一次尝试所的执行步骤要多:

let filtered = items.filter({ 
    for case .foo in [$0] { return true }; return false })

还是很糟糕。

第三次尝试

我个人非常厌恶这个方法,因为我必须要分别为每个枚举值实现一个对应的属性。这简直就是车祸现场:

extension Enum {
    var isFoo: Bool {
        switch self { case .foo: return true; default: return false }
    }
}
let filtered = items.filter({ $0.isFoo })

第四次尝试

这种做法比较恶心,因为它需要占位符来填充 rhs 的值,即便这个值从来没被用过。哦对了,这里就无法传递下划线 (_) 了:

extension Enum {
    static func ~= (lhs: Enum, rhs: Enum) -> Bool {
        let lhsCase = Array(Mirror(reflecting: lhs).children)
        let rhsCase = Array(Mirror(reflecting: rhs).children)
        return lhsCase[0].0 == rhsCase[0].0
    }
}
let filtered = items.filter({ $0 ~= .foo(0) })

第五次尝试

接着我突然灵光一现,我们还可以使用反射 (reflection) 呀!如果不给关联值枚举提供特定值,它就会返回一个 (T) -> Enum 的函数。我写了很多很多,直到我突然意识到枚举的 名称 并没有保留在其反射当中:

import Foundation

extension Enum {
    var caseName: String {
        return "\(Array(Mirror(reflecting: self).children)[0].0!)"
    }
    
    static func ~= <T>(lhs: Enum, rhs: (T) -> Enum) -> Bool {
        let lhsCase = lhs.caseName
        let prefixString = "Mirror for (\(T.self)) -> "
        let typeOffset = prefixString.characters.count
        let typeString = "\(Mirror(reflecting: rhs).description)"
        let rhsCase = typeString.substring(from: typeString.index(typeString.startIndex, offsetBy: typeOffset))
        return true
    }
}

没错……非常难看,此外,还毫无作用。

征集解决方案

我没有深入钻研这个问题,我决定把这个问题作为一个公开的挑战。您是否能想出一个简洁、易读、不怎么可怕(或许我应该说「更优雅」,但拜托,让我任性一下)的方法来实现这个功能呢?我相当怀疑我的第一次尝试可能是最好的,如果这是真的,我会非常难过。

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg

相关文章

  • 挑战:筛选关联值枚举数组

    作者:Erica Sadun,原文链接,原文日期:2017-01-31译者:星夜暮晨;校对:Crystal Sun...

  • Swift 5 枚举

    枚举 关联值: 枚举的成员值和其他类型的值关联储存,存储在枚举变量中 原始值: 枚举成员使用相同的默认值预先对应,...

  • swift中的枚举

    枚举有默认值 原始值不占用枚举内存 关联值

  • Swift与OC的语法简单对比(常用语法二)

    20- 枚举,枚举原始值,枚举相关值,switch提取枚举关联值 Swift枚举: Swift中的枚举比OC中的枚...

  • Swift 2 学习笔记 10.枚举

    课程来自慕课网liuyubobobo老师 枚举 枚举基础 枚举之原始值 枚举之关联值 枚举递归

  • 03.Swift学习

    枚举 关联值 1.有时候会将枚举的成员值跟其他类型的关联存储在一起 原始值 隐式原始值 递归枚举 使用递归枚举的时...

  • Swift使用(四)结构体,类,枚举

    一、枚举 1.1 枚举的定义 1.2 枚举关联值 有时将枚举的成员值跟其他类型的值关联存储在一起,会非常有用 1....

  • Swift中枚举的内存布局

    枚举 枚举的基本用法 关联值(Associated Values) 原始值(Raw Values) 枚举成员可以使...

  • [Swift5.1] 4-枚举

    枚举的基本用法 等价于上边代码 关联值(Associated Values) 有时将枚举的成员值跟其他类型的值关联...

  • 枚举(三)

    关联值 关联值在表达能力上将枚举提升到更高层次。你可以给每个枚举案例关联自定义的相关值。 以下是关联值的特性:1 ...

网友评论

    本文标题:挑战:筛选关联值枚举数组

    本文链接:https://www.haomeiwen.com/subject/qmpwittx.html