Swfit - 控制流

前言

1 - Swift 提供了多种流程控制结构:包括可以多次执行任务的 while 循环;基于特定条件选择执行不同代码分支的 if、guard 和 switch!Swift 中的 switch 语句比 C语言 加强大

① 它可以匹配很多不同的模式,包括范围匹配、元组和特定类型匹配

② 还可以声明为临时常量或变量在 case 作用域内使用

③ 也可以配合 where 来描述更复杂的匹配条件

For-In

1 - 遍历数组、字典、范围区间

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

// 字典
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
    print("\(animalName)s have \(legCount) legs")
}
// 范围 for index in 1...5 { print("\(index) times 5 is \(index * 5)") }

2 - 如果不需要区间序列内每一项的值,可以使用下划线 _ 替代变量名来忽略这个值。下划线符号能够忽略当前值,并且不提供循环遍历时对值的访问

let base = 3
let power = 4
var answer = 1
// 计算 base 这个数的 power 次幂
for _ in 1...power {
    
    answer = answer * base
}
print(answer)// 81

3 - stride(from:to:by:)  | stride(from:through:by:) 两个函数可跳过不需要的标记

let minutes = 60
let minuteInterval = 15
// 15 为间隔遍历
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
    print(tickMark)
}
/* to 遍历结果:开区间 * 0 * 15 * 30 * 45 */
/* through 遍历结果:闭区间
 * 0
 * 15
 * 30
 * 45
* 60 */
 

while | repeat ... while

1 - Swift 提供两种 while 循环形式:while 和 repeat ... while(同 do ... while)

2 - 下面制作一款游戏

① 需求如下

    游戏盘面包括 25 个方格,游戏目标是达到或者超过第 25 个方格则结束!

    每一轮中,你通过掷一个六面体骰子来确定你移动方块的步数,移动的路线由下图中横线所示:如果在某轮结束,你移动到了梯子的底部,可以顺着梯子爬上去;如果在某轮结束,你移动到了蛇的头部,你会顺着蛇的身体滑下去

② 思路

    游戏盘面可以使用一个 Int 数组来表达。数组的长度由一个 finalSquare 常量储存,用来初始化数组和检测最终胜利条件

    梯子底部的方格是一个正值,使你可以向上移动;蛇头处的方格是一个负值,会让你向下移动

 1 let finalSquare = 25
 2 var board = [Int](repeating: 0, count: finalSquare + 1)// 游戏盘面由 26 个 0 的初始化
 3 
 4 // 根据图示,设置前进、后退
 5 board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
 6 board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
 7 
 8 // 记录掷甩子
 9 var diceRoll: Int = 0
10 // 记录移动步数
11 var square:Int = 0
12 
13 
14 // 方式一:使用 while
15 // 游戏没有结束则一直跑循环
16 while square < finalSquare {
17     
18     // 掷骰子
19     diceRoll  = Int(arc4random() % 6)+1;
20     // print(diceRoll)
21     // 移动步数
22     square  = square + diceRoll
23 
24     // 如果玩家还在棋盘上
25     if square < board.count {
26         // 顺着梯子爬上去或者顺着蛇滑下去
27         square += board[square]
28     }
29 }
30 print("Game over!")
31 
32 //-------------------------------------------------------
33 
34 // 条件初始化
35 diceRoll = 0
36 square   = 0
37 
38 // 方式二:Repeat-While
39 repeat {
40     
41     // 顺着梯子爬上去或者顺着蛇滑下去
42     square += board[square]
43     // 掷骰子
44     diceRoll  = Int(arc4random() % 6)+1;
45     // print(diceRoll)
46     // 根据点数移动
47     square += diceRoll
48 } while square < finalSquare
49 print("Game over!")

条件语句

1 - if、if ... else、if ... else if .... 

2 - switch

① 为了匹配某些更特定的值,Swift 提供了几种方法来进行更复杂的模式匹配

let someCharacter: Character = "z"
switch someCharacter {

case "a":
    print("The first letter of the alphabet")

case "z":
    // 在 Swift 中不需要在 case 分支中显式地使用 break 语句
    print("The last letter of the alphabet") // 执行此分支
    // 虽然 break 不是必须的,但你依然可以使用
    break

// 每一个 case 分支都必须包含至少一条语句,如下使用方式报错
// case "k": // 无效:这个分支下面没有语句

// 为了让单个 case 同时匹配多个值,可以将这些值组合成一个复合匹配,用逗号分开
case "m","n":
     print("The letter A")
default:
    print("Some other character")
}

② 区间匹配

// 区间匹配
let approximateCount = 62
let 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(naturalCount) // dozens of

③ 使用元组在同一个 switch 语句中测试多个值

 1 let somePoint = (1, 0)
 2 switch somePoint {
 3 
 4 case (0, 0):
 5     print("\(somePoint) is at the origin")
 6 // 可使用下划线 _ 来匹配所有可能的值
 7 case (_, 0):
 8     print("\(somePoint) is on the x-axis")  // 执行该分支,标记2
 9 case (0, _):
10     print("\(somePoint) is on the y-axis")
11 case (-2...2, -2...2),(1,3):
12     print("\(somePoint) is inside the box") // 此分支不再执行,被标记2截断
13 default:
14     print("\(somePoint) is outside of the box")
15 }

④ 值绑定:case 分支允许将匹配的值声明为临时常量或变量,并且在 case 分支体内使用

let anotherPoint = (2, 0)
switch anotherPoint {

// 常量 x 和 y 的占位符,用于临时获取元组 anotherPoint 的值
// 一旦声明了这些临时的常量,它们就可以在其对应的 case 分支里使用
case let (x, y):
    print("at (\(x), \(y))") // 执行该分支
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)")
}

⑤ 使用 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")
}

⑥ 复合型 Cases

// 复合型 Cases
// 当多个条件可以使用同一种方法来处理时,可以将这几种可能放在同一个 case 后面,并且用逗号隔开
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
    print("\(someCharacter) is a vowel")// 执行该分支
case "b", "c", "d", "f", "g":
    print("\(someCharacter) is a consonant")
default:
    print("\(someCharacter) is not a vowel or a consonant")
}

// 复合匹配同样可以包含值绑定:绑定的值类型必须相同
let stillAnotherPoint = (9, 0)
switch stillAnotherPoint {
case (let distance, 0), (0, let distance):
    print("On an axis, \(distance) from the origin") // 执行该分支
default:
    print("Not on an axis")
}

控制转移语句

1 - 改变代码执行顺序,可以实现代码的跳转。有五种控制转移语句

① continue 

② break

③ 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.

④ return

⑤ throw

标签名

1 - 可以使用标签来标记一个循环体或者条件语句。比如我们学习 while 时写了一个小游戏,现在改变规则:为了获胜,你必须刚好落在第 25 个方块中,就是说如果某次掷骰子使你的移动超出第 25 个方块,你必须重新掷骰子,直到你掷出的骰子数刚好使你能落在第 25 个方块中

 1 // 条件初始化
 2 let finalSquare = 25
 3 var board = [Int](repeating: 0, count: finalSquare + 1)
 4 board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
 5 board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
 6 // 步数
 7 var square = 0
 8 // 骰子
 9 var diceRoll = 0
10 
11 // 标签名 gameLoop
12 gameLoop: while square != finalSquare {
13 
14     diceRoll  = Int(arc4random() % 6)+1;
15     switch square + diceRoll {
16     case finalSquare:
17         // 骰子数刚好使玩家移动到最终的方格里,游戏结束!
18         break gameLoop // 中断 while 循环
19         // 如果 break 后没有使用 gameLoop 标签,那么它中断的是 switch 语句而不是 while 循环
20 
21     // newSquare 等价于 square + diceRoll
22     case let newSquare where newSquare > finalSquare:
23         // 玩家的移动超出最后的方格,那么需要重新掷骰子
24         continue gameLoop
25 
26     default:
27         // 合法移动,做正常的处理
28         square += diceRoll
29         square += board[square]
30     }
31 }
32 print("Game over!")

guard

1 - guard 的执行取决于一个表达式的布尔值,不同于 if 语句,一个 guard 语句总是有一个 else 从句。相比于可以实现同样功能的 if 语句,按需使用 guard 语句会提升我们代码的可读性。注: else 分支必须转移控制以退出 guard 语句出现的代码段,如使用  return、break、continue 或者 throw

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(person: ["name": "John"])
// Hello John!
// I hope the weather is nice near you.

greet(person: ["name": "Jane", "location": "Cupertino"])
// Hello Jane!
// I hope the weather is nice in Cupertino.

检测 API 可用性

1 - Swift 支持检查 API 可用

// 最后一个参数,* 是必须的,用于指定在所有其他平台中
if #available(iOS 10, macOS 10.12, *) {
    // 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API
} else {
    // 使用先前版本的 iOS 和 macOS 的 API
}

 

posted on 2022-04-24 17:39  低头捡石頭  阅读(87)  评论(0编辑  收藏  举报

导航