/***************************** 控制流 Control Flow ***************************/
/**
* For 循环
* While 循环
* 条件语句
* 控制转换语句 (Control Transfer Statements)
* 提前退出
* 检测 API 的可用性
*/
// 类似C语言的流程控制结构,包括可以多次执行的任务For和while循环.基于特定的选择执行不同的分支if , guard 和 switch语句,还有控制流跳转到其他代码的break和continue
// Swift语句中,如果在case分支里无需写break,也不会发生贯穿到下一个case的现象
// case还可以匹配更多的类型模式,包括区间匹配,元祖和特定类型的表述
/**************************** For 循环**************************/
// for-in循环用于对一个集合里面的每一个元素进行遍历执行的一个语句
// for 循环,用来重复执行一系列语句直到达到特定条件,一般都是通过在每次循环完成后增加计数器的数量的值来判定
// for-in
for index in 1...5 {
print("\(index) items 5 is \(index * 5)")
}
// 1 items 5 is 5
// 2 items 5 is 10
// 3 items 5 is 15
// 4 items 5 is 20
// 5 items 5 is 25
// 这个例子中,index是一个每次循环开始时都要自动赋值的常量,这种情况下,index在使用前不需要声明(隐士声明)
// * 如果你不需要知道区间序列内每一项的值,那么你可以使用下划线(_)替代变量名而忽略掉对值的访问
let base = 3
let power = 10
var answer = 1
for _ in 1...power {
answer *= base
}
print("\(base) to the power of \(power) is \(answer)")
// 结果 3 to the power of 10 is 59049
// 使用循环遍历出一个数组的每一个元素
let names = ["Anna","Alex","Brian","Jack"]
for name in names {
print("hello , \(name)")
}
// 结果
/**
hello , Anna
hello , Alex
hello , Brian
hello , Jack
*/
// 遍历字典
// 字典的每一个元素已(key,value)元祖的形式返回
// 可以在for-in循环中使用显示的常量名称来解读[key,value]元祖
let numberOflegs = ["spider":8,"ant":6,"cat":4]
for (animalName,legCount) in numberOflegs {
print("\(animalName)s have \(legCount)")
}
/**
ants have 6
cats have 4
spiders have 8
*/
// 字典元素的遍历顺序和插入顺序可能不同,字典的内容是无序的,所以遍历元素时不能保证顺序.
// For 循环
// 条件判定和递增方法,标准的C样式for循环
for var index = 0;index < 3;index++ {
print("index is \(index)")
}
/**
index is 0
index is 1
index is 2
*/
// 标准格式
//for initialization;condition;increment {
// statements;
//}
// 循环执行流程
/**
* 1,循环首次启动,初始化表达式(initalization expression)被调用一次,用来初始化循环所需的所有常量和变量
* 2,条件表达式(condition expression)被调用.如果表达式调用结果为false,循环结束,继续执行for循环关闭大括号(})之后的代码.如果表达式调用结果为true,则会自行大括号内部的方法
* 3,执行所有语句之后,执行递增表达式(increment expression).通常会增加或减少计数器的值,或者根据语句输出来修改某个初始化的变量.当递增表达式运行完成后,重复执行第2步,条件表达式会再次执行
*/
// 在初始化表达式里面生成的常量或者变量是局部的量,如果想要在循环外使用,要再循环外先声明好再进行循环
var index:Int
for index = 0;index < 3;index++ {
print("index is \(index)")
}
// index is 0
// index is 1
// index is 2
print("The loop statements were executed \(index) times")
// The loop statements were executed 3 times
// While 循环
// while 循环进行一系列的语句直到条件被判定为false.这类循环适合使用在第一代迭代前迭代次数未知的情况下.swift提供两种while循环形式:
/**
* while 循环,每次在循环开始时计算条件是否符合
* repeat-while 循环,每次在循环结束时计算条件是否符合
*/
// while循环从计算单一条件开始,如果条件是true,会重复执行一些列语句,直到条件变成false
// 一般情况下while循环格式
//while condition {
// statements
//}
// 这个是书上的蛇与梯子的游戏,没法复制,看看吧
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
//while square < finalSquare {
// // 模拟掷骰子
// if ++diceRoll == 7 { // 每次自加1,当加到7的时候变为1
// diceRoll = 1
// }
// print("diceRoll is \(diceRoll)")
// // 根据点数移动
// square += diceRoll
// if square < board.count {
// // 如果玩家还在棋盘上,顺着梯子爬上去或者顺子蛇滑下来
// square += board[square]
// print("square is \(square)")
// }
//}
//print("Game over")
// wihle循环开始时,我们并不知道要进行多少次循环,如果满足条件就一直循环下去,只有在达到某个指标之后循环结束
// Repeat-While
// 他是判定循环条件之前,先进性一次循环,感觉就是C的do-while
// 标准格式
/**
repeat {
statements
}while condition
*/
repeat{
print(square)
// 顺着梯子爬上去或者是顺着蛇滑下来
square += board[square]
// 掷骰子
if ++diceRoll == 7{
diceRoll = 1
}
// 根据点数移动
square += diceRoll
}while square < finalSquare
print("Game over")
// 跟上面比较,他是先执行一次再算,算好储备着给下次用
// 上面的方法是当时算,当时就用,所以要内部要判定一下square的值,防止数组越界
/**************** 条件语句 ********************/
// swift提供两种类型的条件语句:if语句和switch语句.
// 通常条件比较简单的话用if语句.而相对复杂的话用swich语句,swich可能情况较多且需要用到模式匹配
// if 语句就是简单的包含一个条件,而且在这个条件为true的时候执行语句
var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
print("It's very cold ,Consider wearing a scarf")
}
// if 语句允许二选一,用else
temperatureInFahrenheit = 40
if temperatureInFahrenheit <= 32 {
print("It's very cold, Consider wearing a scarf")
} else {
print("It's not that cold, Wear a t-shirt")
}
// else 也是可以做判断的
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf")
} else if temperatureInFahrenheit >= 86 {
print("It's really warm, Don't forget to wear sunscreen.")
}
// switch 语句会尝试把某个值与若干个模式进行匹配.
//switch some value to consider {
// case value1:
// respond to value1
// case value2:
// respond to value2
// default:
// otherwise, do something else
//}
let someCharacter:Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(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":
print("\(someCharacter) is a consonant")
default:
print("\(someCharacter) is not a vowel or a consonant")
}
// 输出 "e is a vowel”
// 不存在隐式贯穿
// swift的switch不用写break,不存在隐式贯穿,但是也可以写,不会有影响
// 每一个case分支都必须至少包含一条语句,每个case分支里面不能为空
// swift语句不像C语言一样,他们不会同时匹配"a"和"A"
// 一个case可以包含多个模式,用逗号可以把他们分开
// 也可以贯穿,用fallthrough语句
// 区间匹配
// case分支的模式也可以是一个值的区间.
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
var naturalCount:String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// 输出 There are dozens of moons orbiting Saturn.
// 元组
// 我们可以使用元组在同一个switch语句中测试多个值.
// 元祖中的元素可以是值,也可以是区间.另外,使用(_)来匹配所有可能的值.
// 下面的例子展示了如何用一个(Int,Int)类型的元祖来分来下图中的(x,y):
// 分配一个2 * 2 的正方形上面的点的代码
let somePoint = (1,1)
switch somePoint {
case(0,0):
print("(0,0) is at the origin")
case(_,0): // 默认的值_,这个值不用,可以这么写
print("(\(somePoint.0,0) is on the x-axis")
case (0, _):
print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
print("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// 输出 "(1, 1) is inside the box”
// Swift允许多个case匹配同一个值 ,上面代码里(0,0)点可以匹配四个case
// 如果存在多个匹配,那么只会执行第一个被匹配到的case的分支
// 值绑定
// case分支的模式允许将匹配的值绑定到一个临时的常量或变量,这些常量或者变量在该分支case里可以被引用 -- 这种方法被称为值绑定
// 下面的例子展示了如何在一个(Int,Int)类型的元组中使用值绑定类分类下图中的点(x,y)
let anotherPoint = (2,0)
switch anotherPoint {
case(let x,0):
print("on the x-axis with an x value of \(x)")
case (0,let y):
print("on the y-axis with a y value of \(y)")
case let(x,y):
print("somewhere else at (\(x),\(y)")
}
// 输出 on the x-axis with an x value of 2
/******************** Where **************************/
// case 分支模式可以使用where语句来判断额外的条件
let yetAnotherPoint = (1,-1)
switch yetAnotherPoint {
case let(x,y) where x == y:
print("(\(x),\(y)) is on the line x == y")
case let(x,y) where x == -y:
print("(\(x),\(y)) is on the line x == y")
case let(x,y):
print("(\(x),\(y)) is just some arbitrary point")
}
// 输出 (1,-1) is on the line x == y
// 这个没的说,自己领会吧
// 在case上创建一个元组(x,y),然后根据where判定,如果返回true.就会执行这个分支
/****************** 控制转移语句 ****************/
// 控制转移语句改变你代码的执行顺序,通过它你可以实现代码的跳转.swift有五种控制转移语句
/**
* continue
* break
* fallthrough
* return
* throw
*/
// 这节讨论continue,break和fallthrough语句
// retrun语句在函数章节讲
// throw 语句会在错误抛出章节讨论
/****************** Continue *********************/
// continue 语句告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代.
// 例如在说"本次循环迭代我已经执行完了",但是并不会离开整个循环体
// 注意: 在一个带有条件和递增的for循环体重,调用continue语句后,迭代增加仍会被计算求值.循环体继续像往常一样工作,仅仅只是循环体中的执行代码会被跳动.
// 下面的例子把一个小写字符串中的元音字符和空格字符移除,生成了一个含义模糊的短句:
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
for character in puzzleInput.characters {
switch character {
case "a","e","i","o","u"," ":
continue
default:
puzzleOutput.append(character)
}
}
print(puzzleOutput)
// 输出"grtmndsthnklk"
// 在上面的代码里,只要匹配到元音字母或者空格字符,就调用continue语句,使本次循环迭代结束,从新开始下次循环迭代.这种行为使switch匹配到元音字符和空格字符时不做处理,而不是让每一个匹配到字符都被打印
/******************* Break*******************/
// break 语句会立刻结束整个控制流的执行.
// 当你想要更早的结束一个switch代码块或者小个循环体时,直接使用break
// 循环语句中的break
// 当在一个循环体中使用break时,会立刻中断该循环体的执行,然后跳转出表示循环体结束的大括号(})后的第一行代码.
// Swith语句中的break
// 当在一个switch代码块中使用break,会立刻中断该代码的执行,然后跳转switch代码块结束的大括号(})后的第一行代码.
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 {
print("The integer value of \(numberSymbol) is \(integerValue).")
} else {
print("An integer value could not be found for \(numberSymbol).")
}
// 输出"The integer value of 三 is 3."
/***************** 贯穿 Fallthrough ***********************/
// swift默认在每一个switch case语句里都写有break.不会出现贯穿的现象
// 如果你想要贯穿的效果发生,就在需要贯穿的case语句里加上一个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"
}
print(description)
// 结果是 The number 5 is a prime number,and also an integer
// 带标签的语句
// 在Swift中,你可以循环体嵌套循环体来制造复杂的语句
// 你可以显示的创建break或者是continue语句来显示的指明结束的是哪个循环体
// 产生一个带标签的语句,是通过该语句的关键词的同一行前面放置一个标签,并且该标签还需要一个冒号
// 如下
//labelname:while condition {
// statements
//}
let finalSquare1 = 25
var board1 = [Int](count: finalSquare1 + 1, repeatedValue: 0)
board1[03] = +08; board1[06] = +11; board1[09] = +09; board1[10] = +02
board1[14] = -10; board1[19] = -11; board1[22] = -02; board1[24] = -08
var square1 = 0
var diceRoll1 = 0
gameLoop:while square1 != finalSquare {
if ++diceRoll == 7 {
diceRoll = 1
}
switch square1 + diceRoll1 {
case finalSquare:
// 到达最后一个方块,游戏结束
break gameLoop
case let newSquare where newSquare > finalSquare1:
// 超出最后一个方块.再掷一次骰子
continue gameLoop
default:
// 本次移动有效
square1 += diceRoll1
}
}
print("Game over!")
// 这里给gameLoop生命了一下,
/**
* 如果骰子数刚好使玩家移动到最终的方格里,游戏结束。break gameLoop语句跳转控制去执行while循环体后的第一行代码,游戏结束。
* 如果骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子。continue gameLoop语句结束本次while循环的迭代,开始下一次循环迭代。
* 在剩余的所有情况中,骰子数产生的都是合法的移动。玩家向前移动骰子数个方格,然后游戏逻辑再处理玩家当前是否处于蛇头或者梯子的底部。本次循环迭代结束,控制跳转到while循环体的条件判断语句处,再决定是否能够继续执行下次循环迭代。
*/
// 提前退出
// 像if语句一样,guard的执行取决于一个表达式的布尔值.我们可以使用guard语句来要求条件必须为真时,以执行guard语句后的代码.不同于if代码,一个guard语句总是有一个else分句,如果条件不为真,则执行else分句
func greet(person:[String:String]){
guard let name = person["name"] else {
return
}
print("Hello \(name)")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(["name":"John"])
// prints "Hello John!"
// prints "I hope the weather is nice near you."
greet(["name": "Jane", "location": "Cupertino"])
// prints "Hello Jane!"
// prints "I hope the weather is nice in Cupertino.
// 检测API的可用性
// swift有检测API可用性的内部支持,这可以确保我们不会不小心地使用对于目前部署目标不可用的API.
// 如果不可用,直接报错
// 我们使用一个可用性条件在一个if 或者gurard语句中去有条件的执行一段代码
if #available(iOS 9,OSX 10.10,*){
// 在iOS使用iOS9,在OS X v10.10的API
}else{
// 使用先前版本的API
}
// if段的代码仅会在iOS9及更高版本的系统上执行,在OSX仅在OS X v10.10版本及更高执行.最后一个参数*,是必须写的,用于处理未来潜在的平台
// 一般形式如下:可用性条件获取一些列平台名字和版本.平台名字可以是iOS,OSX或watchOS
// 除了特定的版本号如iOS 8,我们可以指定更小的版本如iOS 8.3
//if #available(platform name version,...,*) {
// statements to execute if the APIs are available
//} else {
// fallback statements to execute if the APIs are unavailable
//}