4.4 条件选择与多分支选择结构
在开发中最重要的两种流程结构即是循环结构与分支结构,循环结构用于处理大量的重复操作,分支结构则用于处理由条件差异而产生的代码分支路径。Swift语言中提供的分支结构有if结构、if-else结构与swtich-case结构。
4.4.1 if与if-else条件选择结构
if与if-else结构语句是Swift语言中用于最基础的分支结构语句,开发者可以使用单个的if语句进行单条件分支,也可以使用if与else组合来实现多条件分支,示例如下:
var c = 10 //进行if条件判断 if c<10 { print(c) } //进行if-else组合 if c>10 { c-=10 print(c) }else{ print(c) } //进行if-else多分支组合 if c>0&&c<10 { print(c) }else if c<=0 { c = -c print(c) }else if c<=10&&c<20{ c-=10 print(c) }else{ print("bigger") }
(1)需要注意,if关键字后面跟的条件必须为严格意义上的逻辑值或者结果为逻辑值的表达式。这点Swift语言和C/Objective-C语言有一定差异。
(2)if-else组合结构每个分支是互斥的,只能有一个分支的代码被执行,条件的判断顺序会从上到下进行,直到找到一个判断条件为真的分支或者最后一个else语句。同时,开发者也可以不加单独的else语句,这种情况下,如果没有条件成立的分支,则任何分支都不会被执行,程序会继续向后执行。
4.4.2 switch-case多分支选择结构
switch语句也被称为开关选择语句,它是通过匹配的方式来选择要执行的代码块,Swift语言中的switch语句更加强大,不像C/Objective-C中的switch语句只能进行int类型值的匹配,Swift语言中的switch语句可以进行任意数据类型的匹配,并且case子句的语法和扩展都更加灵活。使用switch结构进行字符分支匹配的示例如下:
//使用switch语句进行字符分支匹配 switch charac { case "a": print("chara is a") case "b": print("chara is b") case "c": print("chara is c") default ://default用于处理其他额外情况 print("no charac") }
如上代码所示,switch关键字后面需要填写要进行分支匹配的元素,在switch结构中通过子句case的列举进行元素值的匹配,匹配成功后,会执行相应case子句中的代码,如上的代码将打印字符串“chara is b”。default为switch语句中的默认匹配语句,即如果前面所有的case子句都没有匹配成功,则会执行default中的代码,开发者也可以将default子句省略,这时如果所有case子句都没有匹配上,则会跳过switch结构,直接执行后面的代码。
还有一点读者需要注意,在C/Objective-C语言中,case语句不会因匹配成功而中断,如果不进行手动控制,switch结构中的case子句会依次进行匹配执行。举个例子,如果第1个case子句匹配成功,第2个case子句也匹配成功,则第1个case子句和第2个case子句中的代码都会执行,因此C/Objecive-C程序开发中,开发者一般会在每个case子句后面添加break关键字进行手动中断。Swift语句优化了这一点,一个case语句匹配成功后,会自动跳出switch结构,如果不加特殊处理,switch结构中的分支只会被执行一个或者一个也不执行。
switch-case结构也支持开发者在一个case子句中编写多个匹配条件,程序在执行到这个case子句时,只要有一个条件匹配成功,就会执行此case下的代码,示例如下:
//同一个case中可以包含多个分支 switch charac { case "a", "b", "c" : print("chara is word") case "1", "2", "3" : print("chara is num") default : print("no charac") }
case子句的匹配条件也可以是一个区间范围,当要匹配的参数在这个区间范围内时,就会执行此case下的代码,示例如下:
//在case中也可以使用一个范围 var num = 3 switch num { case 1...3 : print("1<=num<=3") case 4 : print("chara is num") default : print("no charac") }
从上面的示例中可以了解,Swift语言中的switch-case结构十分灵活强大,如果将switch-case结构和元组结合使用,开发者在编写代码时将更加灵活多变。首先,对于元组类型参数的匹配,case子句可以进行选择匹配和优化匹配,示例如下:
//使用Switch语句进行元组的匹配 var tuple = (0,0) switch tuple { //进行完全匹配 case (0,1): print("Sure") //进行选择性匹配 case (_,1): print("Sim") //进行元组元素的范围匹配 case(0...3,0...3): print("SIM") default: print("") }
如上代码所示,在进行元组的匹配时,有3种方式可以选择。第1种方式是完全匹配,即元组中所有元素都必须完全相等,才算匹配成功;第2种方式是选择匹配,即开发者只需要指定元组中的一些元素进行匹配,不需要关心的元素可以使用匿名参数标识符来代替,这种方式下,只要指定的参数都相等,就算匹配成功;第三种方式是范围匹配,即相应位置指定的范围包含需匹配元组相应位置的值,就算匹配成功。其中第2种匹配方式可以和第3种匹配方式组合使用。
Swift语言中的case子句中还可以捕获switch元组的参数,在相应的case代码块中可以直接使用捕获到的参数,这在开发中可以简化所编写的代码,示例如下:
var tuple = (0,0) //进行数据绑定 switch tuple { //对元组中的第一个元素进行捕获 case (let a,1): print(a) case (let b,0): print(b) //捕获元组中的两个元素let(a, b) 与 (let a, let b)意义相同 case let(a, b): print(a, b) default: print("") }
这里读者需要注意,要捕获的元素并不能起到匹配的作用,例如元组tuple中有两个元素,如果case条件为(let a,1),则在进行匹配时,会匹配tuple中第2个参数,如果匹配成功,则会将tuple元组的第1个参数的值传递给a常量,并且执行此case中的代码块,在这个代码块中,开发者可以直接使用常量a。因此,要捕获的元素在匹配时实际上充当着匿名标识符的作用,如上代码所示的第3个case子句,其条件为let(a, b),实际上这个条件始终会被匹配成功。并且,如果开发者对元组中的所有元素都进行了捕获,在代码表现上,可以写作(let a, let b),也可以直接捕获整个元组,写作let(a, b),这两种方式只是写法上有差异,在使用时并无差别。
switch-case结构的参数捕获语法在使用起来为开发者带来了不少的便利。然而其也有一个问题,它将所有要捕获的元素都作为匿名参数来进行匹配,有时候并不是开发者想要的结果。例如拿上面的tuple元组示例,开发者需要捕获元组中的第1个元素,同时又需要与第1个元素相关的条件成立时再使case子句匹配成功,针对这种情况,Swift中也提供了相应的办法来处理,可通过在case语句中追加where条件的方式来实现上述需求,示例如下:
//对于进行了数据捕获的Switch-case结构 可以使用where关键字来进行条件判断 switch tuple { case (let a,1): print(a) //当元组中的两个元素都等于0时才匹配成功,并且捕获第一个元素的值 case (let b,0) where b==0: print(b) //当元组中的两个元素相同时,才会进入下面的case case let(a, b) where a==b: print(a, b) default: print("") }