第十章 枚举

枚举是为一组相关值定义的一个通用的类型,使我们在代码中能够安全地操作这些值。

如果对C语言比较熟悉,就会知道在C语言里枚举是给一组相关名称赋予一系列的整型值。但是Swift语言中的枚举更加灵活,不需要为每个枚举成员指定初始值。如果枚举成员被赋予了初始值,这个值可以是字符、字符串、任何整型或浮点类型。

此外,就像其它编程语言中的联合类型或变体类型,Swift语言中的枚举变量可以赋予每个成员任何一种类型的值。我们可以把一系列相关的值定义为一个枚举变量,每个枚举成员都有相应的值与其关联。

枚举作为Swift语言的核心类型拥有强大的能力,它继承了很多一直以来只有类支持的特性,比如提供当前值之外的信息的运算属性,和提供枚举所代表的相关值的函数的实例方法。枚举类型可以通过定义初始化器为每个成员提供初始值,也可以在原始实现上扩展更多的功能,并通过遵循特定协议对外提供标准功能。

关于这些特性的更多信息,请参考属性、方法、初始化、扩展、以及协议。

10.1枚举语法

 我们可以用enum关键字定义枚举变量,并把完整的定义用一对大括号包裹起来:

<此处添加代码10.1-P131>

以指南针的四个方位为例:

<此处添加代码10.1-P132>

枚举中定义的变量的值(如 North、South、East、West)被称作该枚举变量的成员值(或成员)。关键字case表示这一行定义了新的成员值。

注意:与C或者Objective-C语言不同,Swift语言中的枚举类型在创建时不会被赋予一组默认的整型值。上述CompassPoint指南针例子中,North、South、East、West 的值并不是默认为0,1,2,3。相反地,通过 CompassPoint 类型的声明,枚举成员拥有各自独立的类型。

多个成员值可以写在同一行,使用逗号分隔:

<此处添加代码10.1-P132>

每个枚举变量都定义了一个全新的类型。与Swift语言中其它类型一样,枚举变量的命名(比如CompassPoint 和 Planet)必须以大写字母开头,并采用单数而不是复数形式,这样阅读时就一目了然了:

<此处添加代码10.1-P132>

当变量directionToHead 以 CompassPoint 中的一个值初始化时,编译器将推断directionToHead的类型。而一旦把directionToHead 以 CompassPoint 类型声明后,就可以用很简单的方法设置它为 CompassPoint 的其它值:

<此处添加代码10.1-P132>

 directionToHead 的类型已知,我们就可以在赋值时省略它的类型。当遇到显式声明的枚举变量时,这种语法可以让代码更具可读性。

10.2用Swich语句匹配枚举值

我们可以用一个Swich语句匹配一个枚举值:

<此处添加代码10.2-P133>

这段代码可以这样理解:

“考虑directionToHead的值:当它等于.North时,输出 “Lots of planets have a north” ;当它等于.South时,输出 “Watch out for penguins” ”……

就像在流程控制里描述的一样,一个switch 语句在确定枚举成员时必须全面考虑。在上面的例子中,如果case 语句忽略了.West 成员,代码将无法编译,原因是没有考虑到所有 CompassPoint 的成员。这种严格的要求确保了每个枚举成员不会被意外地忽略。

当不能为每一个枚举成员都提供 case 语句时,可以给那些没有显式提到的成员设置一个 default 关键字:

<此处添加代码10.2-P133>

10.3相关值

上一节的例子表明了枚举成员是具有独立定义和类型的值。我们可以为Planet.Earth 赋值为常量或变量,并且之后验证这个值。然而,有的时候存储为除了成员值之外的其他类型的相关值也很有用,因为这可以让我们在声明枚举成员时存储额外的自定义信息,并且允许我们在每次使用这些成员时改变这些信息。

Swift枚举类型可以存储任何指定类型的相关值,并且每个成员的类型可以互不相同。枚举类型与其他编程语言中被我们熟知的鉴别联合类型、标签联合类型或者变异类型相似。

例如,假设在一个存货清单跟踪系统中需要跟踪两种带有不同条形码的产品。一些产品被标记UPC-A的格式的一维条形码,这一格式使用的是0到9的数字。每一个条形码都有一个“号码系统”数字,然后是一个十位的标识符,最后有一个“检验位”数字来验证条形码是否被扫描:


其他产品被标记QR代码格式的二维条形码,这一格式使用ISO 8859-1字符集的任意字符,并且可以表示长达2953个字符的字符串:


 如果我们的存货清单跟踪系统能同时以三个整型数组的形式储存UPC-A格式,并以任意长度的字符串格式保存QR格式的话,那就很方便了。

在Swift语言中,可以这样定义这两种产品的条形码的枚举类型:

<此处添加代码10.3-P135>

这段代码可以这样理解:

“声明一个叫Barcode 的枚举类型,它包含了三个整型数组(Int,Int,Int)的相关值UPC,以及字符串(String)类型的相关值QRCode 。”

这个声明不包含任何确切的整型或字符串类型的值,它只是在 Barcode.UPCA 和Barcode.QRCode 的描述中定义了 Barcode 的枚举变量或常量可以存储的相关值类型。

现在条形码可以通过任意一个类型创建:

<此处添加代码10.3-P135>

这个例子创建了一个名为 productBarcode 的新变量,并赋予了它由三个数值数组关联的 Barcode.UPCA 成员值。在上面的 10 位标识符中出现了一个下划线85909_51226,这是为了让它作为条形码更具可读性。

我们也可以赋予这个产品另外一种类型的条纹码:

<此处添加代码10.3-P136>

这时原有的 Barcode.UPCA 和它关联的数值会被替换成新的 Barcode.QRCode字符串。已经被定义为 Barcode 类型的变量或常量允许使用 .UPCA 或者.QRCode 类型存储数据,但同一时刻只能使用其中一种类型。

与上述相同,使用 switch 语句可以用来检查不同类型的条形码,然而我们可以把关联值提取出来作为 switch 语句的一部分。我们把每个关联值作为常量(使用前缀 let)或者变量(使用前缀 var)提取出来,放在 case 内容里面:

<此处添加代码10.3-P136>

如果一个枚举成员所有的关联类型都能被提取为常量或变量,则可以在枚举成员名称前放一个 let 或者var 声明,简单来说就是这样:

<此处添加代码10.3-P136>

10.4 原始值

前面一节关联值中条形码的例子,讲述了如何为枚举成员声明不同类型的关联值。此外,枚举成员可以预先设定默认值(称为原始值),它们的类型一致。

下面的例子展示了枚举成员的原始ASCII码:

<此处添加代码10.4-P137>

这个例子中,一个名为ASCIIControlCharacter的枚举类型的原始值被定义为Character类型,并为其设置了一些常见的ASCII控制字符。关于字符可以参考字符串与字符一章。

注意原始值和关联值并不一样,就像上述例子中的三个ASCII码,原始值是在代码中第一次定义枚举类型时设置的,并且一个特定枚举成员的原始值始终保持不变。而关联值是根据某一枚举成员创建一个新的常量或变量时设置的,并且每次使用时都可以不同。

原始值可以是字符串、字符、任何整型或浮点数类型。枚举类型声明每一个原始值都必须是唯一的。当原始值为整型并且一些枚举成员没有设置特定值时它们会自增。

下面的枚举类型是上述例子中Planet 枚举类型的一个改进,它使用了整型的原始值代表每个星球距离太阳远近的顺序:

<此处添加代码10.4-P137>

自增就是意味着Planet.Venus的原始值为2,依此类推。

我们可以通过枚举成员的toRaw方法访问其原始值:

<此处添加代码10.4-P137>

通过枚举成员的fromRaw 方法尝试去发现带有特定原始值的枚举成员。下面的例子通过原始值为7找到了Uranus:

<此处添加代码10.4-P138>

然而并不是所有的Int值都会有一个匹配的星球,因此,fromRaw 方法返回的是一个可选的枚举成员。上述的例子中,possiblePlanet 的类型是Planet?或者是optional Planet。

如果试图去找到一个位置为9的星球,fromRaw方法返回的可选的Planet 值为nil:

<此处添加代码10.4-P138>

这个例子使用可选的绑定去试图访问一个原始值为9的星球。如果可以访问,则if let

somePlanet = Planet.fromRaw(9) 这一语句将一个可选 Planet 赋值给 somePlanet。但目前没有办法找到一个位置为 9 的星球,所以 else 分支就被执行了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容