前言:
本篇仅为视频学习笔记
枚举的基本用法
我们开看一下,Swift中的枚举,一说到枚举,在以前学习C语言当中也知道,但是Swift的枚举对比C语言中的枚举,肯定是强大许多的。
回顾一下之前我们C语言的枚举,其实本质就是什么,本质就是整型。以前枚举,就是0、1、2、3、4这些整型,但是swift中的枚举就不一样了。
enum Direction { case north case south case east case west }
根据上面代码,我们来看一下,枚举是怎么定义的?定义非常简单。直接enum,然后Direction是枚举的名称,内部那么多case就代表,枚举有多少个成员。那很明显Direction这个枚举类型,它有4个成员。Direction是方向的意思,它4个成员是东、南、西、北。
上面代码还可以这样写,它们完全是等价的如下:
enum Direction { case north, south, east, west }
那么怎么用呢?很简单,如下:
var dir = Direction.west dir = Direction.east dir = .north print(dir) // north
如果我们要定义一个枚举变量,我们定义一个dir枚举变量,再把Direction.west赋值给它。由于我们Swift编译器会自动推断dir这个类型,所以var dir = 不用声明类型。很明显它就是Direction类型的。
然后,一旦赋值完成之后呢,dir就是Direction这种类型。以后我们可以修改它的值,修改它的值,也只能给它赋值Direction中四个成员中的一个。因为这个类型,已经固定死了,就是Direction。
那么赋值的话,我们可以第一种Direction.east,赋值另外一个值。那么,一当你确定了这个dir是Direction类型,那你可以在赋值过程中可以省略前面的Direction,直接 .north。其实就是case north这个家伙赋值给了dir。
那么到时候,我们直接打印枚举的话,它会将dir成员的名字打印出来。可以自己去尝试一下。
switch dir { case .north: print("north") case .south: print("south") case .east: print("east") case .west: print("west") }
然后,他也可以用在switch语句中,如上。switch这个dir。我们知道swift语句要保证处理所有情况,很明显dir是Direction类型的。Direction类型一共有4个值(成员),我们case 4个,其实就可以了。
关联值 (Associaated Values)
那么,我么再来看一下关联值,我们swift枚举中是可以设置一个关联值的。那是什么意思呢?
★ 有时会将枚举的成员值跟其他类型的关联存储在一起,会非常有用
例子 - 1
相当于就是这样子,如下:
enum Score { case point(Int) case grade(Character) }
比如说,分数Score这个枚举,我们知道分数的话,很多时候分数可能分两种,一种是有具体的值的 case point(Int),比如说你考了96分,98分,100分,那这种分数是有具体值的。但有时候,地方的考试成绩给你的分数,case grade(Character)可能给你拿A,还是拿B,还是拿A+,A、B、C、D 四个等级。
所以说分数可能是有数值的,或者是用A、B、C、D四个字符来表达。所以说,分数有两种情况。所以呢,可以如下面那样定义:
case point(Int) case grade(Character)
也就是说,如果我们要定义一个分数变量的话,如下:
var score = Score.point(96) score = .grade("A")
那么,第一种情况,我们可以Score.point(96),point就是具体的分数,我可以传一个96进去,那么这个96其实就相当于 point(Int)中的Int。那么就这样的话,就将这个96跟我们的score这个枚举变量关联起来了。然后呢,
然后呢,由于我们这个分数呢,也可以是case grade(Character)这种类型,所以呢,我可以给它赋值另外一个** .grade("A")**,但是它接收的是一个字符(Character),比如说,比考的这个分数的等级,你这个成绩是A,那么我们可以传进去一个A给你。
你看,这就很好表达了,成绩有两种,一种是用数值来表达,一种是用字符来表达。
而且,再思考一个问题,枚举一般用在什么地方。是不是你这个变量的取值,就那固定的几种,就应该用枚举。
比如说,一年有多少个季节,这个季节season,这种东西肯定用枚举比较好,因为只有春夏秋冬,这4个季节。所以,季节一般我们用枚举,是最好的。那分数也不是一样吗?我们现在分数就两种,要么就是有数值的,要么是有字符的,说一分数就两种选择,所以把它定义为枚举,还是比较合适的。
switch score { case let .point(i): print(i,"point") case let .grade(i): print("grade",i) } // grade A
那么再来举一个例子,我们先看一下这个switch用在score上面是怎么用的,很简单。一共有两种情况,要么是.point,要么是.grade。这两种嘛,而且呢,由于Int和Character,是到时候可以关联一个值,接收一个值的。
所以呢,建议大家再做case的时候 case let .point(i): ,point里面是要写一个值的,比如说这个i。
那么这个i你要它变成常量呢?还是变量呢?你就可以再左边写一个let或者var,这个取决于你自己。
那我们这个score最后,给它赋值的是score = .grade("A"),很明显这个score是符合这个 case let .grade(i): 的。到时候这个A会赋值给这个 i,所以,最后这个print(i,"grade")打印出来,肯定是grade和这个A。合起来就是 // grade A
例子 - 2
enum Date { case digit(year: Int, month: Int, day: Int) case string(String) } var date = Date.digit(year: 2011, month: 9, day: 10) date = .string("2011-09-10") switch date { case .digit(let year,let month,let day): print(year, month, day) case let .string(value): print(value) }
这是一个日期Date,日期也是一样的,我们可以有两种表达形式,第一种表达形式case digit(year: Int, month: Int, day: Int)是用数字的形式,比如所你传年、月、日,代表日期。第二种表达形式case string(String),你可以直接传一个字符串给我。
我们再来看一下,现在的这个日期Date枚举?日期Date的第一个枚举成员,注意看,跟例1中的Score枚举中的第一个枚举成员,有什么区别。之前Score,它的第一个枚举成员关联的类型,是没有写名称的,但是在Date第一个枚举成员中,我们关联的类型是写名称的,其实,如果你乐意的话,完全可以写几个名称,来表达一下,这三个值代表什么。所以,你看我写了一个year、 month、day。其实这三个名称,这三个标签,你是可以省略的,但有时候,你想让别人明确的知道你想要什么,所以可以写一个标签名。
那么,我们来看一下,那么怎么定义一个这样的变量?其实,很简单,如下:
var date = Date.digit(year: 2011, month: 9, day: 10) date = .string("2011-09-10")
日期有两种表达形式,所以什么情况下用枚举呢?如果你这个类型,只有几个固定的取值的,那么就可以用枚举
那么,这个switch date 也是一样的,那么这个switch再扩展一个,由于digit,它接收了三个家伙,所以肯定有year、month、day的,跟前面讲的那个有什么不一样。
前边讲的这个let修饰词,就是常量修饰词,我是写在这个整体的前面。那么,digit你会发现三个year、month、day是单独写的。
那是,什么意思呢?也就是.digit(let year,var month,let day)中year、month、day哪个是常量,哪个是变量,都收完全可以自己定的。
但是如果你这三个家伙,什么都不写,统一把这个let写到了整体的前面,代表year、month、day都是let 。如果你在前面统一写了一个var,那么year、month、day代表的就是变量,那么我们case一下,就可以把它们当作变量来使用。
case let .string(value):
这个let写在前面,就代表value它是常量,当然这个let 你可以放到value 前面,也是可以的。
var score = Score.point(96) score = .grade("A")
这就是关联值,但时候我这个枚举变量,可以把其它类型的值,关联存储在一起,也就是说这个score变量它的内存中其实是有96这个值的,那么第二个score如果存储这个A的话,也就意味这这个score它内存中是有这个A字符的内容的。
var date = Date.digit(year: 2011, month: 9, day: 10) date = .string("2011-09-10")
还有这个date变量,到时候它的内存中是有2011、9、10这三个整型值,也就是说这三个整型值,其实是存储在date这个枚举变量的内存里面。那么下面这个字符串也是一样的。
关联值,你可以认为将各种类型的数据直接存储在枚举变量里面,这个呢,我们称之为关联值。
★ 必要时,let也可以改成var
关联值举例
比如说,我们讲的密码,我们手机的密码一般有两种,一种是输入密码,一种是输入数字。
数字这个举例是4个,输入4个数字作为你手机的解锁密码,当然你也可以用手势密码。那么,密码输入,既然就两种,我们是完全可以想象成枚举的,因为你就两种取值。
enum Password { case number(Int,Int,Int) case gesture(String) }
所以,我们注意看,你这密码有两种,第一种是数字密码,数字密码我只要求你输入4个,所以是不是,我们就关联4个整型数据。还有一种是手势密码,所以叫gesture。那么手势密码我们就用字符串来表达。
那么怎么用字符串来表达呢?比如说,像这个密码盘我们就可以怎么做呢,我们就可以从左到右,从上到下,给它们编一个序号,比如说:1、2、3、4、5、6、7、8、9。其实如图所示,这个手势密码呢就是12369。那么为什么用字符串呢?我们思考一下,这个手势密码是不是可能很复杂。经过的路径比较多。如果你用整型表达,可能很不完整。那么,我们干脆,用字符串,这样更好。
var pwd = Password.number(3, 5, 7,8) pwd = .gesture("12369")
假如我们的密码是3,5,7,8,手势密码按照刚才的12369,我们就可以这样表达。
enum Password { case number(Int,Int,Int,Int) case gesture(String) } var pwd = Password.number(3, 5, 7,8) pwd = .gesture("12369") switch pwd { case let .number(n1, n2, n3, n4) print("number is",n1,n2,n3,n4) case let .gesture(str) print("gesture is",str) }