swift流程控制_for循环_while循环

分享到:

流程控制

Swift提供所有类似于C语言的流量控制概念。这些包括for和while循环中运行任务多次,if和switch语句在一定条件下执行代码的不同分支;;以及像break和continue语句转换执行流量到代码的另外一点。

除了在C语言中发现的传统的for-condition-increment循环, Swift增加了for-in循环,使它容易迭代arrays、 dictionaries、 ranges、 strings和其他序列。

Swift的switch语句也比在C语言中的副本更加强大。在switch语句中的case语句不会“落入”到下一个 Swift case 语句,避免了由于丢失break语句而导致的一般C语言错误。这些 cases语句可以与许多不同类型的模式匹配,包括范围匹配、元组和特定类型的投射。在switch case语句中匹配的值可以在整个case语句中绑定到临时使用的常量或变量,而复杂的匹配条件可以表示为每个case语句的where子句。

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的数字,如使用封闭范围的操作符表示的(…)。索引值被设置为在范围(1)内的第一个数字, 执行循环语句。在这种情况下,循环只包含一种语句,它为索引当前值从five-times- table中输出一个条目。语句执行后,索引值被更新以包含范围(2)内的第二个值,并再次调用println函数。持续执行本程序,直到该范围的末尾。

在上面的例子中,索引是一个常数,它的值是在每次迭代循环开始时自动设置的。因此,在使用之前,无需声明索引值。在循环声明中,其内容简明扼要隐式的声明了这一点,而不需要let声明的关键词。

注:索引常数只存在循环体范围内。如果你想检查循环完成后的索引值,或者如果你想将它的值作为一个变量使用,而不是一个常量,你必须在循环使用之前自己声明。

如果你不需要此范围内的每一个值,您可以通过在变量名位置处用下划线忽略其值:

 
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的能量)。它用3乘以起始值1(那是3对0的力量),十倍,使用从0到9的半封闭循环。这个计算不需要知道每通过一次循环的各个计数器值——它只需要循环执行正确的次数。下划线字符_(用于循环变量的地方)使单个的值被忽视以及不提供访问每个迭代循环的当前值。

使用for-in循环一个数组进行逐项迭代:

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

您也可以迭代字典以访问其键值对。当dictionary被迭代时,dictionary中的每一项作为一个元组被返回(键,值),并且在for-in循环体中,你可以分解(键,值)元组的成员明确命名使用的常量。在这里,dictionary的键分解为一个称为animalName的常数,并且dictionary的值分解为一个称为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的内容本质上是无序的,并且迭代它们并不能保证他们将被检索的顺序。欲了解更多关于数组和的详细信息,请参阅集合类型。)

除了数组 和 dictionaries外,您还可以使用for-in循环迭代字符串中的字符值:

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

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不需要括号将整个“初始化;条件;增量”的代码块包起来。 循环按照下面流程执行:

  1. 循环第一次进入时,初始化表达式计算一次,设置好循环所需的常量或变量。
  2. 计算条件表达式。如果计算结果为假,循环终止,并且继续执行for循环尾括号(})后面的代码。如果计算结果为真,则执行循环体大括号内的代码。
  3. 在执行完所有语句后,再计算增量表达式。计数器的值可能会增加或减少,或基于语句执行的结果将初始化的变量设定为一个新值。计算完增量表达式,执行返回到步骤2,并且表达条件再一次被计算。

上面描述的循环格式和执行过程可以简略为以下概述(或相当于):

 
initialization
while condition {
statements
increment
}
 

常量和变量在初始化表达式中的声明(比如var指数只是在for循环本身范围内有效。要检索循环结束后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等于假,循环结束。

While循环

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

 

While

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

while循环的一般式为:

 
while condition {
statements
}
 

比如,玩这个名为简单游戏(又称):

snakesAndLadders_2x.png

游戏的规则如下:

游戏版上有25个方块,其目的是落在25个方块上或者之外。

每一轮中,用户摇六面骰子,根据摇出来的数字移动,根据其上带点的箭头沿水平方向。

如果用户最后停留在梯子的底部,可移到前一步。

如果用户最后停留在蛇形的头部,可将其移至底部。

这个游戏板由一个Int值数组表示出来。其大小是基于一个称为finalSquare的常数,这个常数用来初始化数组并在之后检查胜利条件。该游戏板用26个值为零的Int初始化,不是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。为了表述这个动作,board[03]等于+08,相当于一个整数值8(即3和 11的差)。一元运算符加运算符(+)与一元减运算符(-i),小于10的数字用零替代,这样所有板上的定义就一致了。

(风格调整不是必需的,但会使代码更加简洁。)

玩家开始于方块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]
("Game over!")
 

本示例使用一个非常简单的方法来掷骰。它始于diceRoll 0值,而不是一个随机数字发生器。每一次while循环,diceRoll通过自加运算符(++)递增,然后检查是否过大。+ + diceRoll的返回值等于diceRoll自加以后的值。如果这个返回值等于7,骰子值则过大,将其值重置为1。这样,diceRoll的值将总是1,2,3,4,5,6,1,2 等等。

掷骰后,玩家根据diceRol移动前进。有可能骰子的数会让玩家超过方块25,游戏就结束了。应对这种情况下,代码在将存储在board中的值添加到当前的square值之前先检查square的值是否少于board 数组count 属性,如果是,将玩家向上或向下移动到相应梯子或蛇。

这项检查如果没有被执行,board可能试图取得board数组范围以外的值,这将会引发一个错误。如果square现在等于26,代码将试图检查board[26]的值,这个值超过了数组限制。

当前while循环执行结束后,会检查循环的条件以查看循环是否可以再次执行。如果玩家已经移到或移出方块25,循环的条件会计算结果为假,游戏结束。

在这种情况下使用while循环是适当的,因为游戏的长度在while循环开始时是不清楚。让循环一直执行直到特定的满足条件出现。

Do-While 循环

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

下面是do-while循环的一般式为:

 
do {
statements
} while condition
 

再以为例,由while循环改写成do-while循环。FinalSquare, board, square, and diceRoll 的值与while循环以完全相同的方式初始化:

 
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,所以只移动一个梯子赢得这场比赛是不可能的。因此,在本循环中首先检查蛇或梯子会更安全。

游戏一开始,玩家在“方块0”。board[0]总是等于0,没有别的功能:

 
do {
// move up or down for a snake or ladder
square += board[square]
// roll the dice
if ++diceRoll == 7 { diceRoll = 1 }
// move by the rolled amount
square += diceRoll
} while square < finalSquare
println("Game over!")
 

代码检查蛇和梯子后,开始掷骰子,玩家通过diceRol 方块前进。然后终止当前循环。

循环的条件(虽然square< finalSquare)和之前是一样的,但是这一次会在第一次循环的结尾才计算。前一个示例中的do-while循环的结构比while循环更适合本例游戏。在上面的do-while循环中, while循环条件确认square仍在游戏板里面后,立即执行。不需要进行早期版本中游戏的数组越界的检查。

 

条件语句

通常,根据特定条件,需要执行不同的代码块。当错误发生时,您可能希望运行一个额外的代码,或当一个值变得过高或过低时,显示一个消息。要做到这一点,你需要编写条件代码。

Swift提供了两种方法来给代码增加条件分支,称为if语句和switch语句。通常,使用if语句来计算只有只有少量分支的条件。Switch语句更适合于具有多个可能排列的更复杂的条件,并且在模式匹配的情况下可以帮助选择一个适当的代码分支来执行。

If

在其最简单的形式中,if语句仅有一个if条件。只有if条件为真时,if语句才可执行所有语句:

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

前面的示例检查温度是否小于或等于32华氏度(水的冰点)。如果为真,则打印消息。否则不打印消息,并且继续执行if语句大括号之后的代码。 if语句可以提供一套二选一的语句,称为,用于当if条件是假的时候。由else关键字控制这些语句:

 
temperatureInFahrenheit = 40
if temperatureInFahrenheit <= 32 {
println("It's very cold. Consider wearing a scarf.")
} else {
println("It's not that cold. Wear a t-shirt.")
}
// prints "It's not that cold. Wear a t-shirt."
 

始终执行其中一个分支语句。因为温度已经增加到40度,没有冷到要戴着一条围巾,所以else分支被触发。

若考虑增加子句,你可以链接多个if语句:

 
temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
println("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
println("It's really warm. Don't forget to wear sunscreen.")
} else {
println("It's not that cold. Wear a t-shirt.")
}
// prints "It's really warm. Don't forget to wear sunscreen."
 

这里添加的if语句用以应对极端炎热的情况。最后的else子句保留,打印温度既不太热也不太冷的情况。

然而,最后else子句是可选的,并且如果不需要写完整就可以去掉:

 
temperatureInFahrenheit = 72
if temperatureInFahrenheit <= 32 {
println("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
println("It's really warm. Don't forget to wear sunscreen.")
}
 

在这个例子中,温度既不太冷也不太热才能引发if语句或else 条件来打印消息。

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
}
 

每一个switch语句由多个可能的case(情况)组成,其中都用case关键字开头。除了比较特定的值,Swift为每种case提供几种方法来以应对更复杂的匹配模式。这些方法将在本节后面介绍。

每个switch case的主体是代码执行的一个独立的分支,与if语句的分支方式相似。由switch语句决定选择哪个分支语句。被称为所考虑的切换值。

每一个switch语句必须详细。也就是说,每一个所考虑类型可能的值必须与switch中的一个case相匹配。如果不能为每一个可能的值提供一个switch中的case值,可以定义一个默认选取器来解决。选取器用dafault关键字来表示,并且应始终出现在最后。

这个示例使用一个switch语句来考虑一个称为someCharacter的小写字符:

 
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
println("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
println("\(someCharacter) is a consonant")
default:
println("\(someCharacter) is not a vowel or a consonant")
prints "e is a vowel"
 

Switch语句第一条case可匹配了五个小写元音字母。同样,其第二个case匹配所有小写辅音字母。

Switch 中Case中写上所有其他可能的英文字母,使其成为case 的一部分,这是不实际的,所以这switch语句提供了一个default case以匹配其他所有不是元音或辅音的字母。这样保证了switch语句没有遗漏。

无隐式贯穿

相比C和objective - C中的switch语句,Swift中的switch语句不会默认的掉落到每个case的下面进入另一个case.相反,第一个匹配的switch语句当第一个匹配的case一完成, 就完成了它整个的执行。而不需要一个明确的break语句。这使得switch语句比在C语言中使用更安全、更简单,并避免错误地执行多个case。

注:如果需要,你仍然可以在case完成其执行前中断已匹配的 switchcase 详情见打破Switch 语句

每个case语句体必须至少包含一个可执行语句。如果编写以下代码,则本程序无效,因为第一个case为空:

 
let anotherCharacter: 
昵    称:
验证码:

相关文档:

swift
IOS实例
ObjectiveC