swift 枚举详解

参考博客http://c.biancheng.net/cpp/html/2426.html
参考官方文档:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID145

枚举为一系相关联的值定义了一个公共的组类型.同时能够让你在编程的时候在类型安全的情况下去使用这些值。 如果你对C语言很熟悉,你肯定知道在C语言中枚举类型就是一系列具有被指定有关联名称的的整数值.但在Swift中枚举类型就更加灵活了,并且你不必给枚举类型中的每个成员都赋值。如果把一个值(假设值为”raw”)提供给所有的枚举类型当中的成员,那么这个值可以是一个字符串,一个字符,一个整数或者说是一个浮点数. 作为选择,枚举中的成员可以被特别指定为任何不同于其他成员的可以存储的类型,就像是其他语言当中的联合或者变体。你能够将一些相关联的成员定义成一个公共的集合作为枚举的一部分,每个部分都有不同的集合类型并且使用了恰当的类型。

这里有一个例子,定义了一个包含四个方向的罗盘:

enum Compasspoint {

    case north
    case Sourth
    case East
    case West
}

枚举中定义的变量(像上例中north,South,East,West)是枚举的成员变量(或者说成员).关键字case是用来标明这一行将要定义一个新的成员变量

注意:与C或者Objective-C不同的是,在Swift语言中枚举类型的成员初始的时候不会被认赋值成整数值,在Compasspoint这个例子中,north,West认不会隐式的等于0,1,2,3。取而代之的是不同的枚举成员将要用什么类型以及赋值什么值都是可以自己控制的,可以在定义Compasspoint这个枚举的时候指定.

多个成员还可以用一行来定义,他们之间用逗号分割:

enum Plant{
    case Mercury,Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune
}

每个枚举的定义都是定义了一个全新的类型,就像Swfit中的其他的类型一样,枚举的名称(像上边的Compasspoint,Plant)应该是以一个大写字母开头,让他们是单数类型而不是复数类型,从而让他们可以不言而喻:

 var directionToHead = Compasspoint.sourth

当directionToHead在初始化过程中被赋值成Compasspoint中的某一个可能的值的时候,它的类型就可以被推测出来来了。一旦directionToHead被声明成是Compasspoint类型,那么你就可以简短的使用逗号表达式来给它赋值成其他的Compasspoint当中的值了:

directionToHead = .East

directionToHead的类型是已知的了,所以你可以忽略它的类型来给他赋值了。这样使得在使用显示类型的枚举值代码具有很高的可读性。

使用Switch语句来匹配枚举值

你可以通过switch语句来访问单独的某个枚举值:

directionToHead = .south

        switch directionToHead {

        case .north:
            print("Lots of planet have a north")
        case .sourth:
            print("Watch out for penguins")
        case .East:
            print("Where the sun rises")
        case .West:
            print("Where the skies are blue")


        }

你可以这样阅读这段代码:考虑directionToHead的值,如果它等于.north那么就输出”Lost of planets have a north”,如果它等于.south,那么就输出”Watch out for penguins”。

就和在控制流程那一章所讲,一个switch语句被用到判断枚举值的时候,必须要包括所有的枚举成员。假设.West被忽略了,将会导致编译出错,因为它没有考虑到枚举的所有的枚举成员,我们需要全面性的确保枚举的所有成员不被忽略掉.(这个地方我已经验证过了,建议大家也验证下)

如果给考虑每个枚举的成员不合适,你可以提供一个default来覆盖其他没有明确处理的成员:

directionToHead = .East

        switch directionToHead {

        case .north:
            print("Lots of planet have a north")
        case .sourth:
            print("Watch out for penguins")

        case .West:
            print("Where the skies are blue")

        default:
            print("Not a safe place for humans")

        }

关联值

在上一节的示例中显示一个枚举的成员是如何在自己的权利界定(和类型)的值。你可以设置一个常量或变量的值为Planet.Earth ,然后检查这个值。然而,如果在保留成员值的同时能够存储其它类型的关联值将会变得更有意义。这使您能够在保存成员值的同时存储额外的自定义信息,并且允许每次你在代码中使用这些成员值的时候改变这些关联值。在Swift中当你定义一个枚举成员的时候,你可以给他关联任何的类型,而且如果需要的话每个成员可以有不同的关联类型。枚举类型的这个特性和其他语言当中的辨别联合,标记联合或者变体很像。

举个例子,设想一个库存跟踪系统想要通过两种不同的条形码来跟踪产品。一些产品用UPC-A格式的一维条形码标识的,使用0到9的数字。每个条形码当中有一个标识“数字系统“的数字,然后是10个“标识符”数字,最后边一个用来做“检查”的数字,以确保这个条形码被正确的扫描识别:

另一些产品是用QR编码格式的二维码标识的,这种条形码可以使用任何ISO 8859-1的字符而且最大可以编码一个2953字符长度的字符串:

在Swift语言中,一个可以定义两个格式的产品条形码的枚举看起来是这样的:

enum Barcode {
    case UPCA(Int,Int,Int)
    case QRCode(String)
}

你可以这样阅读这段代码:定义了一个叫做Barcode的枚举类型,它可以有一个UPCA成员,这个成员关联了一个包含三个整型数值的元组,同时这个枚举类型还有一个QRCode成员,关联了一个字符串。

这个定义不会生成任何的整型或者字符串值,他只是定义了当一个不可变变量或者变量等于Barcode.UPCA或者Barcode.QRCode的时候它被关联的值的类型
这样一来可以用任意其中一个类型来生成一个新的条形码了:

var productBarcode = Barcode.UPCA(8,85909_51226,3) 

这个例子生成一个新的变量叫做productBarcode,这个变量被关联了一个Barcode.UPCA类型的元组,这个元组的值为(8,8590951226,3),被提供做“标识”的值以及下划线分割了85909_51226,这样做是为了更好的被以条形码读出来。

同样的产品还可以被赋值为另一个条形码类型:

productBarcode = .QRCode("ABCDEFGHIJKLMnop") 

在这一点上,原来的Barcode.UPCA以及关联到的整型值被一个新类型Barcode.QRCode以及与其关联的字符串给替换了。Barcode类型的不可变变量以及可变变量可以存储.UPCA或者.QRCode类型(同时还有与其相关联的值),但是每次都只能存储这两个类型当中的一个

同样,这两个不同的类型可以用Switch语句来做检查。同时,在switch语句中他们相关联的值也可以被获取到。你可以把关联的值当做不可变变量(用let来开头),或者可变变量(用var开头)以在switch的控制体当中使用。

switch productBarcode {

        case .UPCA(let numberSystem,let identifier,let check):
            print("UPC-A with value of \(numberSystem),\(identifier),\(check)")
        case.QRCode(let productCode):
            print("QR code with value of \(productCode)")
        }

如果一个枚举成员关联的所有值都被当做不可变变量或者可变变量来使用,那么你可以在成员名称之前只放一个let或者var来达到目的,简要示例:

switch productBarcode {
    case let .UPCA(numberSystem,identifier,check):
        print("UPC-A with value of \(numberSystem),\(check).")
    case let .QRCode(productCode):
        print("QR code with value of \(productCode).")
}
// 输出 "QR code with value of ABCDEFGHIJKLMnop.” 

原始值

在上一节当中条形码的例子展示了一个枚举类型的成员怎么声明他们可以存储不同类型的关联值。不同于关联值,枚举类型的成员还可以预设置认值(我们叫他原始值),这些值的类型是相同的。

这里有一个枚举成员存储一个ASCII值的例子:

enum ASCIIControlCharacter: Character {
    case Tab = "\t"
    case LineFeed = "\n"
    case CarriageReturn = "\r"
}

这里定义了一个原始值为字符类型的枚举类型ASCIIControlCharacter,而且包含了一些我们常用的控制字符。关于字符类型,你可以在字符串和字符那个章节找到更多的描述。

请注意,原始值与关联值不同。原始值应该是在你定义枚举的代码中被设置为预填充值的,就像上述三个ASCII码。对于一个特定的枚举成员的原始值始终是相同的。关联值是当你创建一个基于枚举的成员的新的常量或变量的时候设置的,并且每次都可以是不同的。

原始值可以是字符串,字符或者其他任何的整型或者浮点型等数字类型。每个原始值在他属的枚举类型定义的时候都应该是不同的。如果原始值是整数类型,那么当其他枚举成员没有设置原始值的时候,他们的原始值是这个整型原始值自增长设置的。

下边这个枚举类型是对之前的Plant枚举类型的改良,新的枚举类型有一个整型的原始值来标识他们在距离太阳的顺序:

enum Planet: Int {
    case Mercury = 1,Neptune
}

自增长的意思就是Planet.Venus的原始值会被设置成2,以此类推。

可以通过枚举成员的rawValue方法获取他的原始值:

let earthOrder = Planet.Earth.rawValue
        print(earthOrder)
        //结果是3

使用枚举成员的(rawValue:)方法来尝试通过一个原始值来寻找他所对应的枚举成员。下面这个例子介绍了怎么通过Uranus的原始值7找到Uranus的:

let possiblePlanet = Planet(rawValue: 7)
        print(possiblePlanet)
        //Optional(swiftDemo.Planet.Uranus)说明是可选择类型,内容可以为nil

 let possiblePlanet = Planet(rawValue: 100)
//输出结果为 nil

递归枚举(Recursive Enumerations)
具体的大家可以到官网去看文档哦,自己的英语水平不是 太高,担心翻译的出入太大误导大家。
参考官方文档:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Enumerations.html#//apple_ref/doc/uid/TP40014097-CH12-ID145

示例如下:

enum ArithmeticExpression {

    case Number(Int)

    indirect case Addition(ArithmeticExpression,ArithmeticExpression)

    indirect case Multiplication(ArithmeticExpression,ArithmeticExpression)

}

当然你也可以这样写:

indirect enum ArithmeticExpression {

     case Number(Int)

     case Addition(ArithmeticExpression,ArithmeticExpression)

     case Multiplication(ArithmeticExpression,ArithmeticExpression)

}

下面我们进行以下测试:

let five = ArithmeticExpression.Number(5)
        let four = ArithmeticExpression.Number(4)
        let sum = ArithmeticExpression.Addition(five,four)
        let product = ArithmeticExpression.Multiplication(sum,ArithmeticExpression.Number(2))

        func evaluate(expression: ArithmeticExpression) -> Int {

            switch expression {

            case let .Number(value):
            return value

            case let .Addition(left,right):
                return evaluate(left) + evaluate(right)

            case let .Multiplication(left,right):
                return evaluate(left) * evaluate(right)
            }

        }

        print(evaluate(product))
        //运行结果为:18

相关文章

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