7.Swift翻译教程系列——控制循环的流程
英语PDF下载链接http://download.csdn.net/detail/tsingheng/7480427
Swift提供了类C语言类似的控制流结构。包含for循环和while循环来多次运行任务,if和switch语句依据不同的条件运行不同的分支代码,break和continue语句将运行流程跳转到其它语句。
除了C里面传统的for-条件-递增循环。Swift还添加了for-in循环使得遍历数组。字典,范围,字符串或者其它序列都非常easy。
Swift的switch语句也要比C语言的switch更强大。
Swift里面某个case语句运行完以后不会再去运行后面的case。避免C语言中因为忘记写break而引起的错误。
case能够匹配多种不同的类型模式,包含范围匹配,元组或者某个特定的类型(casts to a specific type)。
case其中被匹配的值能够与暂时常量或者变量绑定以便在case里面能够使用,复杂的匹配条件能够使用where来表示。
1.for循环
for循环重复运行语句指定次数。
Swift提供两种形式的for循环:
- 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的值使用范围的第二个值2更新,输出语句又被运行了。这个过程一直范围的最后一个值。
上面资历中。index是常量,在每次进行循环的时候自己主动被赋值。这样的情况index没有必要再使用前就声明。
在for-in其中直接使用index就相当于是隐式声明了常量index,都不须要再使用letkeyword。
NOTE 常量index的作用范围不过循环体,假设你想在循环结束以后查看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"这个样例计算base的power次方(样例中是3的10次方)。
样例从1乘3開始,乘了10次,使用了从0到9的半闭区间(这里有问题吗,原文是using a half-closed loop that start with 0 and ends with9,可是样例没有半闭区间也没有0到9啊)。
这个计算不须要知道每次循环计数器的值,仅仅须要每次循环的之后给answer再乘base即可了。
循环变量的位置使用的下划线使得每次循环过程都忽略了循环变量的值,也不提供获取循环变量值的途径了。
使用for-in循环遍历数组中的元素:
let names = ["Anna", "Alex", "Brian", "Jack"] for name in names { println("Hello, \(name)!") } // Hello, Anna! // Hello, Alex! // Hello, Brian! // Hello, Jack!你还能够遍历获取字典的key-value对。
字典的每一个元素以元组(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字典中的元素被遍历的顺序与插入时的顺序是没有关系的。字典中的元素是无序的,遍历的时候也不会保证有什么顺序。
除了数组和字典,你还能够使用for-in循环遍历字符串中的字符:
for character in "Hello" { println(character) } // H // e // l // l // o
除了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 ; condition ; increment外面加括号。
循环的运行顺序例如以下:
- 当第一次进入循环的时候,初始化表达式(initialization)被运行,创建循环可能会用到的常量或者变量。
- 条件表达式被运行。
假设条件表达式结果为false。循环结束,程序运行循环体以后的代码。假设条件表达式为true。就运行循环体。
- 循环体中全部语句都运行完了以后,递增语句才被运行。这条语句一般用来递增或者递减计数器。或者依据语句输出来给已经初始化过的变量更新值。
当递增语句运行完以后。程序回到第二步,条件语句又被运行一次。
循环格式和运行过程能够使用以下等价的形式来表达:
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。循环结束。
2.while循环
while循环重复运行循环体直到条件变为false。这样的循环很适用于在循环体运行之前循环次数未知的情况。Swift提供两种while循环形式:
- while:每次运行循环体之前先计算条件的值。
- do-while:每次运行完循环体之后计算条件的值。
while
while循环以计算条件表达式開始。假设条件为true,循环体就被重复运行知道条件为false,以下是while循环的一般形式
while condition {
statements
}
以下玩一个蛇与梯子的游:
游戏规则:
- 棋盘有25个方格,游戏的目的是要到达或者超过第25格。
- 每次一轮,你须要摇色子来决定你走几格,路线如上图虚线所看到的。
- 假设这一轮结束的时候你到了梯子的底部,就顺着梯子上去。
- 假设你这轮结束的时候碰到了舌头。就顺着射移到以下去。
棋盘能够使用一个Int数组来表示。
棋盘大小使用常量finalSquare存储,用来初始化数组以及后面检查游戏是否通关。
棋盘使用26个0来初始化。而不是25个(下标从0到25):
let finalSquare = 25 var board = Int[](count: finalSquare + 1, repeatedValue: 0)一些涉及到蛇和梯子的方格要被设置为特殊值。挨着梯子底部的方格设置为整数用来向上移动。而挨着蛇头的方格被设置为负数用来向下滑:
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
第3格有一个梯子。能够爬到第11格,所以borad[03]被设置为+8,上面整数前面带加号知识为了看起来更清晰,下标小于10的前面加0仅仅是为了代码整齐。(加号和多余的0都不是必须的。可是这里加上能让代码更清晰。
)
游戏从第0格開始。就是在棋盘左下角之外。第一次掷色子就能移到棋盘上了:
var square = 0 var diceRoll = 0 while square < finalSquare { // roll the dice if ++diceRoll == 7 { diceRoll = 1 } // move by the rolled amount square += diceRoll if square < board.count { // if we're still on the board, move up or down for a snake or a ladder square += board[square] } } println("通关!上面样例里使用非常easy的方式来掷色子。让diceRoll从0開始,每次循环给他加1,++diceRoll返回的是+1后的值,所以当diceRoll+1等于7的时候再把diceRoll设置为1,所以色子的结果是1,2,3,4,5,6,1,2,3...而不是用随机数。")
色子投出来以后,玩家移动diceRoll相应的格数。假设玩家移动以后的格数大于或者等于25就赢了。考虑这样的情况,代码在移动以后检測当前位置是不是比棋盘格数要小。假设比棋盘格数小才加上那一格中的值,假设不小。就说明过关了。那一格中存储的值就是顺着梯子往上爬或者顺着蛇往下爬的格数。
假设不加这个推断,board[square]就有可能要去获取数组board范围外的值,将会引起执行错误。
假设如今squre等于26。代码会去获取board[26]。这个下标超过数组board的范围了。
当前循环体运行完了以后,运行循环条件语句,看循环是否继续运行。假设玩家已经移动到或者超过第25格。循环条件结果就是false,游戏就结束了。
这个样例使用while循环是比較合适的。由于在循环開始之前是不知道游戏要进行的次数的。相反,循环是一直运行到某个特定的条件满足才停止。
do-while
还有一种while循环do-while先运行一次循环体。然后才去推断循环条件。然后循环运行循环体直到循环条件为false。
以下是do-while的一般形式:
do {
statements
} while condition
以下还是蛇与梯子的游戏。这次使用do-while而不是while了。finalSquare,board,square和diceRoll的初始化方式还和上面一样:
let finalSquare = 25 var board = Int[](count: finalSquare + 1, repeatedValue: 0) board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 var square = 0 var diceRoll = 0
这次游戏循环第一步就是检查是否在梯子或蛇上。由于没有梯子能够直接通到第25格,所以玩家不可能通过梯子移动就直接通关。所以循环第一步直接检查蛇或者梯子是安全的。(这里读起来挺别扭的好像没有解释清楚,应该是说用do-while的时候循环第一步就能够直接加上当前格子相应的数字,而不是先掷色子,由于掷色子移动然后就可能到达25格,那你再爬梯子之前就须要前面那个if了,可是假设先爬梯子,就不用推断接着就掷色子。由于从图上看出来爬梯子不可能会通关的。)
游戏開始的时候玩家在第0格上,board[0]还是0,没有什么影响:
do { <span style="white-space:pre"> </span>// move up or down for a snake or ladder <span style="white-space:pre"> </span>square += board[square] <span style="white-space:pre"> </span>// roll the dice <span style="white-space:pre"> </span>if ++diceRoll == 7 { diceRoll = 1 } <span style="white-space:pre"> </span>// move by the rolled amount <span style="white-space:pre"> </span>square += diceRoll } while square < finalSquare println("Game over!")代码检查过梯子或者蛇以后,再通过掷色子移动。然后一轮循环结束。
循环条件是相同的,与以前的,但是这一次,当循环条件只完成了第一个周期将是第一个计算。对于这场比赛,do-while周期比while周期比较合适。在之上do-while循环,当循环条件确定squre不过在黑板上时,他开始下一个周期,而进入循环开始运行squre+=board[square]。这省去了前面square检查边界。