zoukankan      html  css  js  c++  java
  • 关于枚举,你应该了解的东西

    谈到枚举,相信我们大家都并不陌生,大多数编程语言中,都有枚举的实现。关于枚举的定义,我们可以看看这里

    swift 对枚举的进行了更加灵活的实现,比如支持关联值的枚举,还有可以设置原始值的枚举。这都扩展了枚举类型的用途。下面我们就来品味下枚举以及它在 swift 中的实现吧。

    枚举定义语法

    首先,我们来看看在 swift 中定义枚举的语法:

    enum WeekDay {
    
        case Monday
        case Tuesday
        case Wednesday
        case Thursday
        case Friday
        case Saturday
        case Sunday
    
    }
    

    我们注意到,swift 的每个枚举项前面,都使用一个 case 关键字来标识。除了每行声明一个枚举项,也可以将这些枚举项放在一行中声明,每项之间用逗号分隔。

    enum WeekDayInSingleLine {
    
        case Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
    
    }
    

    注意一点,Objective-C 和 C 语言那样, swift 中的枚举项不可以用 0,1,2 这样的数字值来代替。它们有自己的值。

    枚举类型定义好之后,我们就可以将它的枚举值赋值给某个变量:

    var weekday = WeekDay.Tuesday
    

    并且,对于类型明确的变量,我们可以直接省去枚举的类型前缀:

    var day:WeekDay = .Wednesday
    

    枚举的使用

    枚举值可以在 switch 语句中进行匹配:

    switch weekday {
    
    case .Monday:
        println(":(")
    case .Tuesday:
        println(":(")
    case .Wednesday:
        println(":(")
    case .Thursday:
        println(":(")
    case .Friday:
        println(":|")
    case .Saturday:
        println(":)")
    case .Sunday:
        println(":)")
    
    }
    

    switch 语句中的每个 case 中,我们提供各个枚举项的名称:.Monday,.Tuesday 等等。在 swift 中 switch 中匹配枚举项,必须显示的列举出所有的枚举项。也就是对于我们上面表示星期的枚举类型 WeekDay, 我们对它的 switch 语句中必须将所有的枚举项分支都明确的写出来。否则就会有编译错误。

    这个机制也体现了 Swift 类型安全的核心思想。如果我们觉得每个枚举项都要明确的指定行为比较麻烦,我们还可以使用 default 分支来对于其余的枚举项定义行为:

    switch weekday {
    
    case .Saturday:
        println(":)")
    case .Sunday:
        println(":)")
    default:
        println(":(")
    
    }
    

    总之,无论用 default 也好,还是明确对每一个枚举项指定行为也好,在 Swift 中,我们都必须对枚举类型下的每个值,指定确定的行为。不能漏掉其中任何一个可能性。

    关联值(Associated Values)

    在 Swift 中,我们还可以定义这样的枚举类型,它的每一个枚举项都有一个附加信息,来扩充这个枚举项的信息表示,这又叫做关联值。加入我们有一个枚举类型 Shape 来表示形状。
    这个形状可以是矩形,也可以是圆形,等等。而每种具体的形状又对应了不同的属性,比如矩形有长,宽,圆形有,圆心,半径,等等。那么枚举的关联值就可以帮我们解决这个问题:

    enum Shape {
    
        case Rectangle(CGRect)
        case Circle(CGPoint,Int)
    
    }
    

    我们看到,每个枚举项的后面,都包含了一对括号,这里面定义了这个枚举项的关联值的类型。对于 Rectangle 我们使用一个 CGRect 来表示他的原点和长宽属性。
    而对于 Circle,我们使用一个包含了 CGPointInt 类型的元组(Tuple) 来表示这个圆的圆心和半径。

    这样我们在初始化枚举类型的时候,我们就可以根据每个枚举项的关联值类型,为它指定附加信息了:

    var rect = Shape.Rectangle(CGRectMake(0, 0, 200, 200))
    var circle = Shape.Circle(CGPointMake(25, 25), 20)
    

    这样的枚举用法,是不是觉得非常方便呢, 有木有脑洞小开的感觉呢,嘿嘿~

    小憩一下,喝杯咖啡 ☕️,我们继续哦。

    ......

    我们再看一下,带有关联值的枚举项在 switch 语句中的用法:

    switch(rect) {
    
    case .Rectangle(let rect):
        println("this is a rectangle at (rect)")
    case let .Circle(center, radius):
        println("this is a circle at (center) with radius (radius)")
    
    }
    

    我们在 case 后面用一对括号来输出枚举项的关联值,可以用 let 或者 var 关键字,分别作为常量和变量进行输出。我们这里这样来使用 case .Rectangle(let rect)。对于关联值是包含多个值的元组类型的,我们可以将 let 关键字放置在枚举项类型的前面,这样就可以不用对每个关联值都声明 let 关键字了,let .Circle(center, radius)。

    原始值(Raw Values)

    我们刚刚了解了关联值类型的枚举的使用,Swift 的枚举类型还提供了另外一个叫做原始值(Raw Values)的实现。和关联值不同,它为枚举项提供一个默认值,这个默认值是在编译的时候就确定的。而不像关联值那样,要再实力化枚举值的时候才能确定。

    这也就是说,原始值对于同一个枚举项都是一样的。而关联值对于同一个枚举项只是值的类型相同,但具体的取值也是不同的。

    下面我们来看一下定义枚举原始值 (Raw Values) 的方法:

    enum WeekDayWithRaw : String {
    
        case Monday = "1. Monday"
        case Tuesday = "2. Tuesday"
        case Wednesday = "3. Wednesday"
        case Thursday = "4. Thursday"
        case Friday = "5. Friday"
        case Saturday = "6. Saturday"
        case Sunday = "7. Sunday"
    
    }
    

    还是表示星期的枚举类型,我们对每个枚举项都定义了一个默认的原始值,注意一下我们定义枚举的第一行代码,enum WeekDayWithRaw : String 我们在枚举定义的最后,多加了一个 String
    关键字,这就表示这个枚举的原始值(Raw Values) 是 String 类型的。

    在我们下面的定义中,也体现了这一点。对于所有的枚举项,我们赋给的原始值都是 String 类型的。

    定义好了原始值后,我们就可以用枚举项的 rawValue 属性来输出它:

    println(WeekDayWithRaw.Saturday.rawValue)  //6. Saturday
    

    我们还可以通过原始值(Raw Values) 来初始化枚举类型:

    let day = WeekDayWithRaw(rawValue: "3. Wednesday")
    

    这个初始化方法的返回值是一个 Optionals。所以我们可以用 Optionals 的组合链来使用它的返回值:

    if let day = WeekDayWithRaw(rawValue: "3. Wednesday") {
        println(day)
    }else{
        println("init fail")
    }
    

    返回值为 Optionals 的类型,代表这个方法可以返回一个具体的值,也可以返回 nil, 因为我们传入初始化方法的原始值,可能会不等于我们预设的那几个值,比如我们这样初始化一个枚举:

    let day = WeekDayWithRaw(rawValue: "No Exist Value")
    

    如上面所示,"No Exist Value" 这个值和我们定义个原始值列表中任何一项都不对应,所以这个初始化是会失败的,在这种情况下初始化方法会返回 nil,来表示初始化失败。

    所以基于这种情况,我们需要对返回值进行判断,这也就是我们上面的 if 判断的用处所在:

    if let day = WeekDayWithRaw(rawValue: "3. Wednesday") {
        println(day)
    }else{
        println("init fail")
    }
    

    关于 Optionals 的更多内容,可以参考 浅谈 Swift 中的 Optionals 这篇文章。

    以上就是我们关于 Swift 中枚举的介绍了,不知各位是否有所收获呢,我们从这个枚举的使用方法中,不难体会到 Swift 中对类型安全 理念的实践,比如 switch 语句中强制的分支实现,以及从原始值初始化的 Optionals 返回值。都体现了这一理念。

    大家还可以在这里下载我们的 playground 文件:

    Enumeration.playground

    更多精彩内容,请扫码关注微信公众号

  • 相关阅读:
    @字节跳动8年老Android面试官谈;Context都没弄明白凭什么拿高薪?
    @阿里面试官:Android面试这些原理都给我讲明白了,最低都是20k起步!
    @以后面试官再问你三次握手和四次挥手,直接把这一篇文章丢给他
    @备战2020年金三银四,看这一篇面试文章就够了(合适各级Java人员)
    字节跳动面试,第三面挂了,这原因我服了!
    太可惜了,四面字节跳动,我的offer竟被一道“算法题”给拦截了
    @java2019面试题北京
    @2019.07 Android 面试真题集锦
    2018 Java线程热门面试题,你知道多少?
    阿里大厂的148道核心面试题,(程序员必备学习方向)offer收割机 全会月薪50k不难
  • 原文地址:https://www.cnblogs.com/theswiftworld/p/swift_enum.html
Copyright © 2011-2022 走看看