Swift 流程控制

network | | 访问(72)

Swift提供了所有c类语言的控制流结构。包括for和while循环来执行一个任务多次;if和switch语句来执行确定的条件下不同的分支的代码;break和continue关键字能将运行流程转到你代码的另一个点上。

除了C语言传统的for-condition-increment循环,Swift加入了for-in循环,能更加容易的遍历arrays, dictionaries, ranges, strings等其他序列类型。

Swift的switch语句也比C语言的要强大很多。 Swift中switch语句的case语句不会“掉入”下一个case,避免了c语言忘记写break语句产生的错误。 case可以匹配许多不同的模式,包括范围匹配,元组匹配或者抛给指定的类型。匹配值在一个case条件下可以绑定到临时常量或变量,可以在case的代码块中使用,复杂匹配条件下可以表示为每一个case的条件。

For Loops - For循环

for循环用来多次执行一组语句 ,Swift提供了两种形式:

for-in执行范围,序列,集合或级数等每一项中的一组语句

for-condition-increment执行一组语句直到确定的条件出现,通常在每一个循环结束前递增一个计数

For-In

使用for-in来遍历集合中的项目,比如数组的范围,排列中的项或者字符串中的字符。

下面的例子打印了表中的5个元素

for index in 1...5 {
    println("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5 
// 2 times 5 is 10 
// 3 times 5 is 15 
// 4 times 5 is 20 
// 5 times 5 is 25

例子中被迭代集合的项是一个封闭范围内从1到5的数字,就是上面标识为封闭范围操作符的 (...)。 Index的值被设为第一个数据的范围(1), 然后执行循环中的语句。在本例中,循环只包含了一句话,根据index现有的值打印5次乘法表的一个结果。当执行完语句之后,index的值被更新为范围中的第二个值,然后再次调用println函数。这个操作会一直持续,直到范围的终点。

在上面的例子中,index是一个常量,它的值在每次迭代的开始时自动初始化,使用前不会被声明,就是简单的将其隐性声明纳入循环的声明,不需要使用let来声明关键字。

注意:Index常量仅仅存在于循环的范围内。如果你想要在循环之后得到index的值,或者想要使用index的值作为变量,你必须在循环之前声明它。

如果不需要范围的值,可以用下划线替代变量名来忽略这些值:

let base = 3
let power = 10
var answer = 1
for _ in 1...power {
    answer *= base
}
println("\(base) to the power of \(power) is \(answer)")
// prints "3 to the power of 10 is 59049"

例子中计算两数相乘(在本例中,3乘以10)。乘法初始值为1,每次乘3,乘10次,使用半封闭循环从0到9。这个计算不需要通过循环来知道每个计数器的值--仅仅只需要执行正确的循环次数。下划线操作符 _ (用于替代循环变量)将忽略掉个体值,并且在每一次循环迭代期间不给现有的变量提供访问。

使用for-in循环来迭代出array中的每一个项:

let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
    println("Hello, \(name)!")
}
// Hello, Anna!
// Hello, Alex!
// Hello, Brian!
// Hello, Jack!

同样可以迭代字典来访问其中的键值对。当迭代字典时里面的每一个项都以(key,value)元组的形式来返回,你可以在for-in的循环体中分解 (key, value) 元组的成员,把成员作为显性命名的常量来使用。下面例子,字典的key被分解为animalName的常量,字典的值被分解名为legCount的常量:

let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
    println("\(animalName)s have \(legCount) legs")
}
// spiders have 8 legs
// ants have 6 legs
// cats have 4 legs

Dictionary中的项的迭代顺序可能跟它们插入时的顺序不一样。因为Dictionary中的内容本质上是无序的,所以迭代它们不能保证检索时的顺序。

除了排列和字典,for-in循环还能迭代字符串中的Character(字符):

for character in "Hello" {
    println(character)
}
// H
// e
// l
// l
// o

For-Condition-Increment For-条件-递增

除了for-in循环,Swift还支持传统C语言按条件递增的for循环

for var index = 0; index < 3; ++index {
    println("index is \(index)")
}
// index is 0
// index is 1
// index is 2

这是常用的形式:

for <initialization>; <condition>; <increment> {
    <statements>
}

封号把循环定义隔为了三个部分,跟C语言一样。然而与C不同的是,Swift不需要用括号把 “初始化; 条件; 增量” 的代码块包起来。

循环按照下面流程执行:

当循环第一次进入,initialization expression(初始化表达式)计算一次,设置好循环所需的常量或者变量。

计算condition expression(条件表达式)。如果计算结果为false(假),循环终止,并继续执行for循环尾括号(})后面的代码。如果结果为(true)真,则执行循环体大括号内的代码。

在所有的语句执行完后,计算increment expression(增量表达式)。计数器可能递增或递减,也可能根据语句执行的结果将初始化变量设为新的值。计算完增量表达式返回到第2步,条件表达式再次被计算。

上面描述的循环体的形式和执行过程可以简单的等同于:

<initialization> while <condition> {
    <statements>
    <increment>
}

常量和变量在初始化表达式中的声明(比如var index = 0)只在for循环自己内部有效。如果需要知道index最终的值,必须在循环开始前声明index:

var index: Int for index = 0; index < 3; ++index {
    println("index is \(index)")
}
// index is 0
// index is 1
// index is 2
println("The loop statements were executed \(index) times")
// prints "The loop statements were executed 3 times"

注意,循环完成后index最终的值是3,不是2。最后一次执行增量表达式调用了++index,把index设为3,使得index<3等于false,循环结束。

While Loops - While循环

while循环在条件变为false前执行一组语句,这类循环最好用在第一个迭代开始前并不知道迭代器的数字的时候。Swift提供了两种while循环:

while 在每次通过循环的开头计算条件

do-while 在每次通过循环的结尾计算条件

while

一个while循环开始于计算单个的条件,如果条件为true,一组语句将重复直到条件变为false。

这是常见的while形式:

while <condition> {
    <statements>
}

Do-While

While循环的另一个形式是do-while,在考虑循环条件前先执行一次整个循环体,然后再继续重复循环直到条件为false。

下面是do-while的常见形式:

Conditional Statements - 条件语句

编程中常常根据不同的条件执行不同的代码,你可能会要代码在出错后运行额外的语句,或者当数值越界时展示一个消息。我们可以用conditional(条件)来实现。

Swift提供两种方式来添加代码的分支,常见的if和switch语句。显然,用if语句来计算只有少量分支的的条件,而Switch用于更复杂的情况,特别是在模式匹配的时候有助于选择合适的代码分支来执行。

If

在下面最简单的例子里,if语句有一个if条件。所有的语句都只有在if条件为true的情况下才执行:

var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
    println("It's very cold. Consider wearing a scarf.")
}
// prints "It's very cold. Consider wearing a scarf."

Switch

Switch语句用一个值来匹配相对应的几个匹配模式。然后执行相对应的代码块,基于一开始匹配成功的模式。switch语句提供了应对多种选择情况的处理来替代if语句。

最简单的形式,switch比较一个值对应的一个或者多个相同形式的值:

switch some value to consider {
    case value 1:
        respond to value 1
    case value 2, value 3:
        respond to value 2 or 3
    default:
        otherwise, do something else
}

Control Transfer Statements - 控制转移语句

控制转移语句能改变已经执行代码的顺序,能使代码跳转到别的部分。Swift有四个句子:

continue  break  fallthrough  return

Continue

Continue语句告诉循环体终止现在的操作,然后开始迭代下一个循环。好像在说“我这次迭代做完啦”,总之不会离开循环体。

注意:在for-condition-increment循环中,调用了continue后累加器依旧会计算。循环会继续像平时一样工作,只有循环体中的代码会被跳过。

下面例子中从一个小写字符串中移除了所有的元音和空格,创建了个字谜短语:

let puzzleInput = "great minds think alike"
var puzzleOutput = ""
for character in puzzleInput {
    switch character {
        case "a", "e", "i", "o", "u", " ":
            continue
        default:
            puzzleOutput += character
    }
}
println(puzzleOutput)
// prints "grtmndsthnklk"

上面代码里,只要匹配到元音字母或空格,就会触发continue关键字。使本次迭代立即终止,然后直接跳入下次迭代的开头。这个方式使得switch代码块能匹配(和忽略)元音字母与空格,比用代码块把每一个要打印字符都匹配一次的好。

Break

Break语句能立即终止整个控制流。可以根据你想要的在switch或循环语句里的任何地方终止整个执行。

Break in a Loop Statement - 循环中的Break

当在循环体中使用break,循环会立即停止,并将控制流带到循环体括号(})后方的第一行代码里。循环体里其他的代码不会被执行,也不会开始下一次迭代。

Break in a Switch Statement - Switch中的break

在switch里使用break,switch语句会立即终止,并将控制流带到switch语句括号(})后方的第一行代码里。

这种特性可以用于switch里匹配(或忽略)一个或多个case。因为Swift的switch是穷举的,并且不允许有空case的,有时候要慎重的匹配和为了使意图明显而忽略了case。当switch匹配了break语句,case中的break能直接终止整个switch。

注意:一个switch的case只能包含一个作为编译错误的注释。注释不是语句,不会导致switch的case被忽略。只能使用break语句来跳过case。

下面的例子中switch有一个字符值,并且判断四种语言之一中是否有数字符号。一个简单的switch中包含了多个值:

let numberSymbol: Character = "三"
// Simplified Chinese for the number 3
var possibleIntegerValue: Int?
switch numberSymbol {
    case "1", "١", "一", "๑":
        possibleIntegerValue = 1
    case "2", "٢", "二", "๒":
        possibleIntegerValue = 2
    case "3", "٣", "三", "๓":
        possibleIntegerValue = 3
    case "4", "٤", "四", "๔":
        possibleIntegerValue = 4
    default:
        break
}
if let integerValue = possibleIntegerValue {
    println("The integer value of \(numberSymbol) is \(integerValue).")
} else {
    println("An integer value could not be found for \(numberSymbol).")
}
// prints "The integer value of 三 is 3."

例子中通过检查numberSymbol判断是否是拉丁语,阿拉伯语,中文或者泰文符号来得到1至4的数字。如果匹配成功,其中的一个case里会赋给可选型Int变量possibleIntegerValue一个合适的整型值。

在switch语句执行完成后,例子里用了可选型绑定来确定值是否被发现。possibleIntegerValue变量有一个隐性的初始值nil,具有可选型的优点。只有在前四个case中,当possibleIntegerValue被赋了实际的值可选绑定才会成功。

在上面例子中列出所有可能的字符值不太实际,所以default能提供一个没任何字符被选中情况下的容器。这的default不用执行任何操作,只写个简单的break。一旦default被匹配,break语句立即终止switch,并继续执行 if let语句。

Fallthrough

Swift中的Switch不会掉下到case的下方并进入下一个case。因此,整个switch语句毁在第一个匹配的case完成后结束。相反,C语言要求你在每个case的末尾插入一个break来防止掉入。相比于C语言,Swift的switch禁止默认掉入让更加简洁和可控,这样避免了执行多个case的错误。

如果你确实需要C式的掉入特性,你可以使用fallthrough关键词。下面的例子用fallthrough来创建一段描述数字的文本:

let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
    case 2, 3, 5, 7, 11, 13, 17, 19:
        description += " a prime number, and also" fallthrough
    default:
        description += " an integer."
}
println(description)
// prints "The number 5 is a prime number, and also an integer."

例子中声明了一个名为description的String型变量并分派一个初始值。然后函数用switch匹配integerToDescribe的值。如果integerToDescribe的值符合素数列表中的一项,最后的description会增加一段字符,注意数字都是素数。然后用fallthrough关键字让代码“掉到”default里。default的代码中再额外的给字符串添加些描述,最后switch结束。

如果integerToDescribe不跟素数表中任何一项匹配,那根本就不会匹配switch的第一个case。这里面没有其他的case,因此integerToDescribe直接进入default容器。

在switch执行完成后,数字的描述用println函数打印出来。在本例中,5是正确的答案。

注意:fallthrough关键字不检查case里的条件,会直接掉入下一个case。fallthrough简单的让代码执行到下一个case(或default)的代码块中,和标准C语言的特性一样。