美文网首页
Enums, Equatable, and exhaustive

Enums, Equatable, and exhaustive

作者: TCJing | 来源:发表于2017-08-17 17:06 被阅读0次

    英文原文
    现在你有这样的一个枚举:

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

    当这两个参数拥有相同的case的时候这两个case就会被得到处理,除此之外,添加了一个默认模式(default)来返回false。这样来使用时简单、简短和正确的:

     Expression.number(1) == .number(1)
     Expression.number(1) == .string("a")
    

    Defult case 的使用将使得穷尽的检查失去效果

    然而,你的实现由一个严重的瑕疵,如果你再添加一个case到你的枚举当中去,编译器将不会提醒你,你的==实现现在是不完整的。让我们在枚举中添加第三个case:

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

    对于编译器而言,这是完全正确的。在下面的执行中,你的代码将返回错误的结果:

    Expression.bool(true) == .bool(true)
    

    switch语句中的默认子句使编译器的详尽性检查无效。出于这样的原因,通常的建议就是在switch语句中应该尽量避免使用default。

    如果可以避免,不要在switch中使用default

    二次方爆炸模型

    当然没有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
            }
        }
    }
    

    啊,这样写一点也不好玩,当有更多的case的时候,这将变得很糟糕,switch语句必须区分的状态数量与枚举中的case数量二次方增长。

    从二次方到线性增长

    您可以通过_占位符模式这样的一些更加聪明的方式来使其更加易于管理。虽然我们在上面看到一个默认子句是不够的,但是每种情况都是一个模式。 switch语句中的最后六个模式变成三个:

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

    通过这种方式来做更好的是,枚举中的每个附加情况只会向switch语句增加两条线 - 它不再二次扩展。并且您可以从编译器的穷举检查中获益:添加新的case会在==中引发错误。

    相关文章

      网友评论

          本文标题:Enums, Equatable, and exhaustive

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