博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为什么不要在枚举和 Equatable 中使用 default case?
阅读量:6999 次
发布时间:2019-06-27

本文共 2374 字,大约阅读时间需要 7 分钟。

作者:Ole Begemann,,原文日期:2017-03-06

译者:;校对:;定稿:

假设你有一个 Swift 的枚举:

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

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

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) // → trueExpression.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, rhs: Expression)        -> Bool {        switch (lhs, rhs) {        case let (.number(l), .number(r)): return l == r        case let (.string(l), .string(r)): return l == r        case let (.bool(l), .bool(r)): return l == r        case (.number, .string),             (.number, .bool),             (.string, .number),             (.string, .bool),             (.bool, .number),             (.bool, .string): return false        }    }}

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

从平方增长到线性增长

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

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        case let (.bool(l), .bool(r)): return l == r        case (.number, _),             (.string, _),             (.bool, _): return false        }    }}

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

Sourcery

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

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 。

转载地址:http://cfdvl.baihongyu.com/

你可能感兴趣的文章
用Canvas写一个炫酷的时间更新动画玩玩
查看>>
windows sever2003安装Wamp 2.5不成功——VC 11不支持Windows Server 2003和win XP?
查看>>
分享一下上个星期的香港行程
查看>>
HUT-1675 找啊找啊找GF DP
查看>>
使用jQuery插件jScrollPane开发Mac OSX Lion风格的滚动条
查看>>
使用jQuery开发iOS风格的页面导航菜单
查看>>
SQL:事务(1)
查看>>
js事件定义方式和获取事件对象event总结
查看>>
Erlang练习-UDP
查看>>
ACE定时器
查看>>
tar解压错误
查看>>
Java NIO与IO的差别和比較
查看>>
spark web ui中的skipped的含义
查看>>
深入理解Linux内核-块设备驱动程序
查看>>
yield return 和yield break
查看>>
念念不忘SERVLET
查看>>
L11,one good turn deserves another
查看>>
Code::Blocks设置支持C++ 11
查看>>
Performance Tips
查看>>
mfc显示静态图片最简单的方法
查看>>