Swift学习:2.5 控制流
参考Swift 官方教程《The Swift Programming Language》中文版
控制流Swift提供了类似 C 语言的流程控制结构,包括可以多次执行任务的 除了 C 语言里面传统的 for 条件递增( Swift 的 For 循环
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
例子中用来进行遍历的元素是一组使用闭区间操作符( 上面的例子中,
如果你不需要知道区间内每一项的值,你可以使用下划线( let base = 3
let power = 10
var answer = 1
for _ in 1...power {
answer *= base
}
println("(base) to the power of (power) is (answer)")
// 输出 "3 to the power of 10 is 59049"
这个例子计算 base 这个数的 power 次幂(本例中,是 使用 let names = ["Anna","Alex","Brian","Jack"]
for name in names {
println("Hello,(name)!")
}
// Hello,Anna!
// Hello,Alex!
// Hello,Brian!
// Hello,Jack!
你也可以通过遍历一个字典来访问它的键值对(key-value pairs)。遍历字典时,字典的每项元素会以 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 character in "Hello" {
println(character)
}
// H
// e
// l
// l
// o
For条件递增(for-condition-increment)除了 for var index = 0; index < 3; ++index {
println("index is (index)")
}
// index is 0
// index is 1
// index is 2
下面是一般情况下这种循环方式的格式:
和 C 语言中一样,分号将循环的定义分为 3 个部分,不同的是,Swift 不需要使用圆括号将“initialization; condition; increment”包括起来。 这个循环执行流程如下:
上述描述和循环格式等同于:
在初始化表达式中声明的常量和变量(比如 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")
// 输出 "The loop statements were executed 3 times
注意 While 循环
While
下面是一般情况下
下面的例子来玩一个叫做蛇和梯子(Snakes and Ladders)的小游戏,也叫做滑道和梯子(Chutes and Ladders): 游戏的规则如下:
游戏盘面可以使用一个 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 号方格,我们使用 玩家由左下角编号为 0 的方格开始游戏。一般来说玩家第一次掷骰子后才会进入游戏盘面: var square = 0
var diceRoll = 0
while square < finalSquare {
// 掷骰子
if ++diceRoll == 7 { diceRoll = 1 }
// 根据点数移动
square += diceRoll
if square < board.count {
// 如果玩家还在棋盘上,顺着梯子爬上去或者顺着蛇滑下去
square += board[square]
}
}
println("Game over!")
本例中使用了最简单的方法来模拟掷骰子。 掷完骰子后,玩家向前移动 如果没有这个检测( 当本轮
Do-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
游戏开始时,玩家在第 0 个方格上, do {
// 顺着梯子爬上去或者顺着蛇滑下去
square += board[square]
// 掷骰子
if ++diceRoll == 7 { diceRoll = 1 }
// 根据点数移动
square += diceRoll
} while square < finalSquare
println("Game over!")
检测完玩家是否踩在梯子或者蛇上之后,开始掷骰子,然后玩家向前移动 循环条件( 条件语句根据特定的条件执行特定的代码通常是十分有用的,例如:当错误发生时,你可能想运行额外的代码;或者,当输入的值太大或太小时,向用户显示一条消息等。要实现这些功能,你就需要使用条件语句。 Swift 提供两种类型的条件语句: If
var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
println("It's very cold. Consider wearing a scarf.")
}
// 输出 "It's very cold. Consider wearing a scarf."
上面的例子会判断温度是否小于等于 32 华氏度(水的冰点)。如果是,则打印一条消息;否则,不打印任何消息,继续执行 当然, 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.")
}
// 输出 "It's not that cold. Wear a t-shirt."
显然,这两条分支中总有一条会被执行。由于温度已升至 40 华氏度,不算太冷,没必要再围围巾——因此, 你可以把多个 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.")
}
// 输出 "It's really warm. Don't forget to wear sunscreen."
在上面的例子中,额外的 实际上,最后的 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.")
}
在这个例子中,由于既不冷也不热,所以不会触发 Switch
每一个 case 都是代码执行的一条分支,这与
下面的例子使用 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")
}
// 输出 "e is a vowel"
在这个例子中,第一个 case 分支用于匹配五个元音,第二个 case 分支用于匹配所有的辅音。 由于为其它可能的字符写 case 分支没有实际的意义,因此在这个例子中使用了默认分支来处理剩下的既不是元音也不是辅音的字符——这就保证了 不存在隐式的贯穿(No Implicit Fallthrough)与 C 语言和 Objective-C 中的
每一个 case 分支都必须包含至少一条语句。像下面这样书写代码是无效的,因为第一个 case 分支是空的: let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a":
case "A":
println("The letter A")
default:
println("Not the letter A")
}
// this will report a compile-time error
不像 C 语言里的 一个 case 也可以包含多个模式,用逗号把它们分开(如果太长了也可以分行写):
区间匹配(Range Matching)case 分支的模式也可以是一个值的区间。下面的例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式: let count = 3_000_000_000_000
let countedThings = "stars in the Milky Way"
var naturalCount: String
switch count {
case 0:
naturalCount = "no"
case 1...3:
naturalCount = "a few"
case 4...9:
naturalCount = "several"
case 10...99:
naturalCount = "tens of"
case 100...999:
naturalCount = "hundreds of"
case 1000...999_999:
naturalCount = "thousands of"
default:
naturalCount = "millions and millions of"
}
println("There are (naturalCount) (countedThings).")
// 输出 "There are millions and millions of stars in the Milky Way."
元组(Tuple)你可以使用元组在同一个 下面的例子展示了如何使用一个 let somePoint = (1,1)
switch somePoint {
case (0,0):
println("(0,0) is at the origin")
case (_,0):
println("((somePoint.0),0) is on the x-axis")
case (0,_):
println("(0,(somePoint.1)) is on the y-axis")
case (-2...2,-2...2):
println("((somePoint.0),(somePoint.1)) is inside the box")
default:
println("((somePoint.0),(somePoint.1)) is outside of the box")
}
// 输出 "(1,1) is inside the box"
在上面的例子中, 不像 C 语言,Swift 允许多个 case 匹配同一个值。实际上,在这个例子中,点(0,0)可以匹配所有四个 case。但是,如果存在多个匹配,那么只会执行第一个被匹配到的 case 分支。考虑点(0,0)会首先匹配 值绑定(Value Bindings)case 分支的模式允许将匹配的值绑定到一个临时的常量或变量,这些常量或变量在该 case 分支里就可以被引用了——这种行为被称为值绑定(value binding)。 下面的例子展示了如何在一个 let anotherPoint = (2,0)
switch anotherPoint {
case (let x,0):
println("on the x-axis with an x value of (x)")
case (0,let y):
println("on the y-axis with a y value of (y)")
case let (x,y):
println("somewhere else at ((x),(y))")
}
// 输出 "on the x-axis with an x value of 2"
在上面的例子中, 这三个 case 都声明了常量 一旦声明了这些临时的常量,它们就可以在其对应的 case 分支里引用。在这个例子中,它们用于简化 请注意,这个 在上面的例子中, Wherecase 分支的模式可以使用 下面的例子把下图中的点(x,y)进行了分类: let yetAnotherPoint = (1,-1)
switch yetAnotherPoint {
case let (x,y) where x == y:
println("((x),(y)) is on the line x == y")
case let (x,y) where x == -y:
println("((x),(y)) is on the line x == -y")
case let (x,y):
println("((x),(y)) is just some arbitrary point")
}
// 输出 "(1,-1) is on the line x == -y"
在上面的例子中, 这三个 case 都声明了常量 就像是值绑定中的例子,由于最后一个 case 分支匹配了余下所有可能的值, 控制转移语句(Control Transfer Statements)控制转移语句改变你代码的执行顺序,通过它你可以实现代码的跳转。Swift有四种控制转移语句。
我们将会在下面讨论 Continue
下面的例子把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句: let puzzleInput = "great minds think alike"
var puzzleOutput = ""
for character in puzzleInput {
switch character {
case "a","u"," ":
continue
default:
puzzleOutput.append(character)
}
}
println(puzzleOutput)
// 输出 "grtmndsthnklk"
在上面的代码中,只要匹配到元音字母或者空格字符,就调用 Break
循环语句中的 break当在一个循环体中使用 Switch 语句中的 break当在一个 这种特性可以被用来匹配或者忽略一个或多个分支。因为 Swift 的
下面的例子通过 let numberSymbol: Character = "三" // 简体中文里的数字 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).")
}
// 输出 "The integer value of 三 is 3."
这个例子检查 当 在上面的例子中,想要把 贯穿(Fallthrough)Swift 中的 如果你确实需要 C 风格的贯穿(fallthrough)的特性,你可以在每个需要该特性的 case 分支中使用 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)
// 输出 "The number 5 is a prime number,and also an integer."
这个例子定义了一个 如果 当
带标签的语句(Labeled Statements)在 Swift 中,你可以在循环体和 为了实现这个目的,你可以使用标签来标记一个循环体或者 产生一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,并且该标签后面还需带着一个冒号。下面是一个
下面的例子是在一个带有标签的
如果某次掷骰子使你的移动超出第 25 个方块,你必须重新掷骰子,直到你掷出的骰子数刚好使你能落在第 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
var square = 0
var diceRoll = 0
这个版本的游戏使用 该 gameLoop: while square != finalSquare {
if ++diceRoll == 7 { diceRoll = 1 }
switch square + diceRoll {
case finalSquare:
// 到达最后一个方块,游戏结束
break gameLoop
case let newSquare where newSquare > finalSquare:
// 超出最后一个方块,再掷一次骰子
continue gameLoop
default:
// 本次移动有效
square += diceRoll
square += board[square]
}
}
println("Game over!")
每次循环迭代开始时掷骰子。与之前玩家掷完骰子就立即移动不同,这里使用了
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |