为什么不要在枚举和 Equatable 中使用 default case?

作者:Ole Begemann,原文链接,原文日期:2017-03-06
译者:Cwift;校对:numbbbbb;定稿:CMB

假设你有一个 Swift 的枚举:

enum Expression {
    case number(Double)
    case string(String)
}

你希望它遵守 Equatable 协议。由于该枚举具有关联值,必须手动添加,所以需要实现 == 函数

extension Expression: Equatable {
    static func ==(lhs: Expression,rhs: Expression)
        -> Bool {
        switch (lhs,rhs) {
        case let (.number(l),.number(r)): return l == r
        case let (.string(l),.string(r)): return l == r
        default: return false
        }
    }
}

这里处理了参数类型相同的两种情况,比较类型不同时会执行 default case 并返回 false。这种做法简单直接,也没错:

Expression.number(1) == .number(1) // → true
Expression.number(1) == .string("a") // → false

Default case 会使得枚举对穷尽的检查无效

然而这段代码一个严重的缺陷:如果你在枚举中添加一个 case,编译器不会警告你当前枚举的实现是不完整的。现在给枚举添加第三种 case:

enum Expression {
    case number(Double)
    case string(String)
    case bool(Bool)
}

只要能通过编译器的检查,那么这种行为就是合理的。但执行以下操作时代码会返回错误的结果:

Expression.bool(true) == .bool(true) // → false!

switch 语句中的 default case 会使编译器对枚举的检查无效。所以,通常来说尽可能避免在 switch 语句中使用 default。

<center><font size=4>如果可能,尽量不要在 switch 语句中使用 default</font></center>

模式匹配大爆炸

没有 default case 的缺点也很明显:你需要写更多的模式匹配代码。下面是完全覆盖三种 case 的写法:

extension Expression: Equatable {
    static func ==(lhs: Expression,.string(r)): return l == r
        case let (.bool(l),.bool(r)): return l == r
        case (.number,.string),(.number,.bool),(.string,.number),(.bool,.string): return false
        }
    }
}

o(>﹏<)o!写起来一点都不愉快,而且当枚举的 case 增加时会变得更糟。switch 语句必须区分的状态数会随着枚举中 case 的数量呈平方增长。

从平方增长到线性增长

_ 占位符可以简化你的 switch 语句。虽然不能使用 default 语句,但是我们可以把上一段代码最后的六行简化成三行:

extension Expression: Equatable {
    static func ==(lhs: Expression,_),_): return false
        }
    }
}

这个方案更好,枚举中每增加一个 case,switch 语句只会增加两行,不再是平方级的增加。而且你保留了编译器穷尽检查的优势:添加一个新 case,编译器会报 == 的错误

Sourcery

如果你觉得重复代码还是太多,可以看看 Krzysztof Zabłocki 开发的代码生成工具 Sourcery。在类似的应用场景中,它可以自动为枚举以及其他类型生成 Equatable 协议所需的代码(并且不断更新生成代码)。

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

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...