为有牺牲多壮志,敢教日月换新天。

Swift5.4 语言指南(八) 控制流

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/9726471.html 
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

热烈欢迎,请直接点击!!!

进入博主App Store主页,下载使用各个作品!!!

注:博主将坚持每月上线一个新app!!!

Swift提供了各种控制流语句。其中包括while多次执行任务的循环。if,,guardswitch语句根据特定条件执行不同的代码分支;和诸如和的语句breakcontinue以将执行流转移到代码中的另一点。

Swift还提供了for-in循环,使您可以轻松地遍历数组,字典,范围,字符串和其他序列。

Swift的switch语句比许多类似C的语言中语句要强大得多。案例可以匹配许多不同的模式,包括间隔匹配,元组和强制转换为特定类型。switch案例中的匹配值可以绑定到要在案例主体中使用的临时常量或变量,并且复杂的匹配条件可以用where每种案例子句来表示

循环内

您可以使用for-in循环遍历序列,例如数组中的项目,数字范围或字符串中的字符。

本示例使用for-in循环遍历数组中的项目:

  1. let names = ["Anna", "Alex", "Brian", "Jack"]
  2. for name in names {
  3. print("Hello, \(name)!")
  4. }
  5. // Hello, Anna!
  6. // Hello, Alex!
  7. // Hello, Brian!
  8. // Hello, Jack!

您还可以遍历字典以访问其键值对。迭代字典时,字典中的每个项目都作为元组返回,并且您可以将元组的成员分解为显式命名的常量,以在-循环的主体中使用在下面的代码示例中,字典的键被分解为常量,而字典的值被分解为常量(key, value)(key, value)forinanimalNamelegCount

  1. let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
  2. for (animalName, legCount) in numberOfLegs {
  3. print("\(animalName)s have \(legCount) legs")
  4. }
  5. // cats have 4 legs
  6. // ants have 6 legs
  7. // spiders have 8 legs

a的内容Dictionary本质上是无序的,对其进行迭代并不能保证它们的检索顺序。特别是,您将项目插入Dictionary的顺序并没有定义它们的迭代顺序。有关数组和字典的更多信息,请参见Collection Types

您还可以使用for-in具有数字范围的循环。本示例在五倍表中打印前几个条目:

  1. for index in 1...5 {
  2. print("\(index) times 5 is \(index * 5)")
  3. }
  4. // 1 times 5 is 5
  5. // 2 times 5 is 10
  6. // 3 times 5 is 15
  7. // 4 times 5 is 20
  8. // 5 times 5 is 25

使用封闭范围运算符(所示,要迭代的序列的范围是从1到的一个数字5范围(含...)。的值index设置为范围(1)中的第一个数字,并执行循环内的语句。在这种情况下,循环仅包含一个语句,该语句从5倍表中打印出的当前值index执行该语句后,的值将index更新为包含范围(2)中的第二个值,然后print(_:separator:terminator:)再次调用函数。此过程一直持续到到达范围的终点为止。

在上面的示例中,index是一个常数该常数的值在循环的每次迭代开始时自动设置。因此,index不必在使用前声明它。只需将其包含在循环声明中即可隐式声明它,而无需let声明关键字。

如果不需要序列中的每个值,则可以使用下划线代替变量名来忽略这些值。

  1. let base = 3
  2. let power = 10
  3. var answer = 1
  4. for _ in 1...power {
  5. answer *= base
  6. }
  7. print("\(base) to the power of \(power) is \(answer)")
  8. // Prints "3 to the power of 10 is 59049"

上面的示例将一个数字的值计算为另一个数字的幂(在这种情况下,3为的幂10)。使用以开头和结尾的封闭范围,将起始值1(即3的幂0)乘以310倍对于此计算,不需要每次通过循环都使用单独的计数器值-代码只需按正确的次数执行循环即可。下划线字符()代替循环变量会导致各个值被忽略,并且在每次循环迭代时都无法访问当前值。110_

在某些情况下,您可能不想使用封闭范围,包括两个端点。考虑在表盘上每分钟绘制刻度线。60要从0分钟开始绘制刻度线使用半开范围运算符(..<)包括下限,但不包括上限。有关范围的更多信息,请参见范围运算符

  1. let minutes = 60
  2. for tickMark in 0..<minutes {
  3. // render the tick mark each minute (60 times)
  4. }

有些用户可能希望其UI中的刻度线更少。他们可能更喜欢每5分钟获得1分。使用此stride(from:to:by:)功能可以跳过不需要的标记。

  1. let minuteInterval = 5
  2. for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
  3. // render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
  4. }

也可以使用以下范围来提供封闭范围stride(from:through:by:)

  1. let hours = 12
  2. let hourInterval = 3
  3. for tickMark in stride(from: 3, through: hours, by: hourInterval) {
  4. // render the tick mark every 3 hours (3, 6, 9, 12)
  5. }

While循环

while循环执行一组语句,直到条件变为false当第一次迭代开始之前不知道迭代次数时,最好使用此类循环。Swift提供两种while循环:

  • while 每次循环执行时都会评估其条件。
  • repeat-while在每次循环结束时评估其条件。

尽管

一个while循环开始通过评估一个条件。如果条件是true,则重复一组语句,直到条件变为为止false

这是while循环的一般形式

  1. while condition {
  2. statements
  3. }

这个例子玩一个简单的蛇和梯子游戏(又称滑梯和梯子):

../_images/snakesAndLadders_2x.png

游戏规则如下:

  • 木板有25个正方形,目标是在25个正方形上或超出正方形。
  • 玩家的起始方块为“零方块”,位于棋盘左下角。
  • 每转一圈,您将滚动一个六边形的骰子,并按照上面虚线箭头指示的水平路径移动该正方形数。
  • 如果您的转弯在梯子的底部结束,那么您将向上移动该梯子。
  • 如果转弯结束于蛇的头部,则将其向下移动。

游戏板由一组Int值表示。它的大小基于一个称为的常数finalSquare,该常数用于初始化数组,并在示例中的稍后部分检查是否有获胜条件。因为玩家从棋盘上开始,在“零平方”上,所以棋盘被初始化为26个零Int值,而不是25个值。

  1. let finalSquare = 25
  2. var board = [Int](repeating: 0, count: finalSquare + 1)

然后将一些正方形设置为对蛇和梯子具有更特定的值。带有梯形底脚的正方形的正数可以使您上板,而带有蛇形头的正方形的负数可以将您下移到板上。

  1. board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
  2. board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

方3含有梯子的底部的是移动你到平方11.为了表示这一点,board[03]是等于+08,这相当于一个整数值8(之间的差311)。为了对齐值和语句,一元加运算符(+i)与一元减运算符(-i显式结合使用,并且将小于10零的数字填充为零。(两种样式技术都不是绝对必要的,但是它们会导致代码更整洁。)

  1. var square = 0
  2. var diceRoll = 0
  3. while square < finalSquare {
  4. // roll the dice
  5. diceRoll += 1
  6. if diceRoll == 7 { diceRoll = 1 }
  7. // move by the rolled amount
  8. square += diceRoll
  9. if square < board.count {
  10. // if we're still on the board, move up or down for a snake or a ladder
  11. square += board[square]
  12. }
  13. }
  14. print("Game over!")

上面的示例使用一种非常简单的方法来掷骰子。而不是生成随机数,而是从diceRoll开始0每次通过while循环时,diceRoll将其递增1,然后检查其是否变得太大。每当此返回值相等时7,骰子掷骰就变得太大,并重置为1其结果是序列diceRoll值,这总是12345612等。

掷骰子后,玩家向前移动diceRoll方块。掷骰子可能会将玩家移至25号方格之外,这种情况下游戏结束了。为了应对这种情况,代码检查square是否小于board数组的count属性。如果square有效,则将存储的值board[square]添加到当前square值,以使播放器在任何梯子或蛇上上下移动。

笔记

如果未执行此检查,则board[square]可能尝试访问board数组范围之外的值,这将触发运行时错误。

然后,当前while循环执行结束,并检查循环的条件以查看是否应再次执行循环。如果玩家移动到或超过平方数25,则循环条件评估为false,游戏结束。

一个while循环是在这种情况下,适当的,因为游戏的长度是不是在开始明确while循环。而是执行循环,直到满足特定条件为止。

重复时

while循环的另一种形式repeat--while循环,考虑循环条件之前,会执行一次循环循环。然后,它将继续重复循环,直到条件为为止false

笔记

repeat-while环斯威夫特类似于一个do-while循环其他语言。

这是repeat-while循环的一般形式

  1. repeat {
  2. statements
  3. } while condition

这又是蛇和梯子的例子,写成repeat-while循环而不是while循环。的值finalSquareboardsquare,和diceRoll以完全相同的方式初始化为一个while循环。

  1. let finalSquare = 25
  2. var board = [Int](repeating: 0, count: finalSquare + 1)
  3. board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
  4. board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
  5. var square = 0
  6. var diceRoll = 0

在此版本的游戏中,循环中第一个动作是检查梯子或蛇。棋盘上没有梯子可以使玩家直奔25平方,因此不可能通过爬梯子来赢得比赛。因此,作为循环中的第一个动作,检查蛇或梯子是安全的。

在游戏开始时,玩家处于“零平方”。board[0]总是相等0,没有效果。

  1. repeat {
  2. // move up or down for a snake or ladder
  3. square += board[square]
  4. // roll the dice
  5. diceRoll += 1
  6. if diceRoll == 7 { diceRoll = 1 }
  7. // move by the rolled amount
  8. square += diceRoll
  9. } while square < finalSquare
  10. print("Game over!")

代码检查完蛇和梯子后,掷骰子,玩家向前移动diceRoll方块。然后,当前循环执行结束。

循环的条件()与以前相同,但是这次直到循环的第一次运行结束时才进行评估-循环的结构上一个示例中循环更适合此游戏上面-循环中,总是在循环的条件确认仍然在板上后立即执行此行为消除了前面介绍的游戏循环版中看到的数组边界检查的需要while square finalSquarerepeatwhilewhilerepeatwhilesquare += board[square]whilesquarewhile

条件语句

根据特定条件执行不同的代码段通常很有用。您可能想在发生错误时运行额外的一段代码,或者在值变得太大或太低时显示一条消息。为此,您需要将部分代码设为条件

Swift提供了两种向代码中添加条件分支的方法:if语句和switch语句。通常,您使用该if语句评估只有少数可能结果的简单条件。switch语句更适合于具有多个可能排列的更复杂条件,并且在模式匹配可以帮助选择合适的代码分支来执行的情况下很有用。

如果

以最简单的形式,该if语句只有一个if条件。仅当条件为时,它才执行一组语句true

  1. var temperatureInFahrenheit = 30
  2. if temperatureInFahrenheit <= 32 {
  3. print("It's very cold. Consider wearing a scarf.")
  4. }
  5. // Prints "It's very cold. Consider wearing a scarf."

上面的示例检查温度是否小于或等于32华氏度(水的冰点)。如果是,则会打印一条消息。否则,将不打印任何消息,并且在if语句的右大括号之后继续执行代码

对于条件为的情况,if语句可以提供另一组语句,称为else子句这些语句由关键字指示iffalseelse

  1. temperatureInFahrenheit = 40
  2. if temperatureInFahrenheit <= 32 {
  3. print("It's very cold. Consider wearing a scarf.")
  4. } else {
  5. print("It's not that cold. Wear a t-shirt.")
  6. }
  7. // Prints "It's not that cold. Wear a t-shirt."

这两个分支之一始终被执行。由于温度升高到40华氏度,因此不再足够寒冷以致建议戴围巾,于是else触发分支。

您可以将多个if语句链接在一起以考虑其他子句。

  1. temperatureInFahrenheit = 90
  2. if temperatureInFahrenheit <= 32 {
  3. print("It's very cold. Consider wearing a scarf.")
  4. } else if temperatureInFahrenheit >= 86 {
  5. print("It's really warm. Don't forget to wear sunscreen.")
  6. } else {
  7. print("It's not that cold. Wear a t-shirt.")
  8. }
  9. // Prints "It's really warm. Don't forget to wear sunscreen."

在这里,if添加了一条额外的声明以应对特别温暖的温度。最后的else子句仍然保留,并且它会在温度既不高又不太冷的情况下显示响应。

else但是,final子句是可选的,如果不需要完整的条件集,则可以将其排除。

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

由于温度既不太冷也不太热,无法触发if条件,因此不会打印任何消息。else if

转变

一条switch语句考虑一个值,并将其与几种可能的匹配模式进行比较。然后,它根据成功匹配的第一个模式执行适当的代码块。一个switch语句提供的另一种if用于应对多种潜在状态的语句。

switch语句以最简单的形式将一个值与一个或多个相同类型的值进行比较。

  1. switch some value to consider {
  2. case value 1:
  3. respond to value 1
  4. case value 2,
  5. value 3:
  6. respond to value 2 or 3
  7. default:
  8. otherwise, do something else
  9. }

每个switch语句都包含多种可能的情况,每种情况都以case关键字开头除了与特定值进行比较之外,Swift还为每种情况提供了几种方法来指定更复杂的匹配模式。这些选项将在本章后面介绍。

就像if语句的主体一样,每个语句case都是代码执行的单独分支。switch语句确定应选择哪个分支。此过程称为打开要考虑的值。

每个switch声明都必须详尽无遗也就是说,所考虑类型的每个可能值都必须与其中一种switch情况匹配如果不合适为每个可能的值都提供一个大小写,则可以定义一个默认大小写以覆盖所有未明确寻址的值。此默认情况由default关键字指示,并且必须始终显示在最后。

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

  1. let someCharacter: Character = "z"
  2. switch someCharacter {
  3. case "a":
  4. print("The first letter of the alphabet")
  5. case "z":
  6. print("The last letter of the alphabet")
  7. default:
  8. print("Some other character")
  9. }
  10. // Prints "The last letter of the alphabet"

switch语句的第一种情况相匹配的英文字母,第一个字母a,它的第二种情况下的最后一个字母匹配,z因为switch必须为每一个可能的字符的情况下,不只是每一个字母,这个switch语句使用default情况,以配合以外所有的字符az该规定确保该switch陈述是详尽无遗的。

没有隐式掉线

switchC和Objective-C中的switch语句相比,Swift中的语句不会掉入每种情况的底部,默认情况下不会进入下一种情况。而是,在switch第一个匹配的switch情况完成后,整个语句将立即完成执行,而无需显式break语句。这使得该switch语句比C语言中语句更安全,更易于使用,并且避免switch了错误地执行多个情况。

笔记

尽管break在Swift中不是必需的,但是您可以使用break语句来匹配和忽略特定的情况,或者在该情况完成执行之前中断匹配的情况。有关详细信息,请参见在Switch语句中中断

每个案例的主体必须包含至少一个可执行语句。编写以下代码是无效的,因为第一种情况为空:

  1. let anotherCharacter: Character = "a"
  2. switch anotherCharacter {
  3. case "a": // Invalid, the case has an empty body
  4. case "A":
  5. print("The letter A")
  6. default:
  7. print("Not the letter A")
  8. }
  9. // This will report a compile-time error.

switchC中语句不同,此switch语句与"a"都不匹配"A"而是报告不包含任何可执行语句的编译时错误这种方法避免了从一个案例到另一个案例的意外失败,并使意图更清晰的更安全的代码成为可能。case "a":

为了使switch与匹配二者的单一情况下"a""A",这两个值组合成的化合物的情况下,用逗号分隔的值。

  1. let anotherCharacter: Character = "a"
  2. switch anotherCharacter {
  3. case "a", "A":
  4. print("The letter A")
  5. default:
  6. print("Not the letter A")
  7. }
  8. // Prints "The letter A"

为了便于阅读,还可以将多行案例写在多行上。有关复合案例的更多信息,请参见复合案例

笔记

要在特定switch情况结束时明确掉线,请使用fallthrough关键字,如Fallthrough中所述

间隔匹配

switch可以检查案例中的是否包含在间隔中。本示例使用数字间隔为任意大小的数字提供自然语言计数:

  1. let approximateCount = 62
  2. let countedThings = "moons orbiting Saturn"
  3. let naturalCount: String
  4. switch approximateCount {
  5. case 0:
  6. naturalCount = "no"
  7. case 1..<5:
  8. naturalCount = "a few"
  9. case 5..<12:
  10. naturalCount = "several"
  11. case 12..<100:
  12. naturalCount = "dozens of"
  13. case 100..<1000:
  14. naturalCount = "hundreds of"
  15. default:
  16. naturalCount = "many"
  17. }
  18. print("There are \(naturalCount) \(countedThings).")
  19. // Prints "There are dozens of moons orbiting Saturn."

在上面的示例中,approximateCount在一条switch语句中求值每个case比较该值与一个数字或间隔。因为值的approximateCount落差介于12到100之间,naturalCount所以将为其分配值,并且执行从语句中转移出来"dozens of"switch

元组

您可以使用元组在同switch一条语句中测试多个值元组的每个元素都可以针对不同的值或值的间隔进行测试。或者,使用下划线字符(_),也称为通配符模式,以匹配任何可能的值。

下面的示例采用一个(x,y)点,表示为type的简单元组,并将其分类在该示例之后的图上。(Int, Int)

  1. let somePoint = (1, 1)
  2. switch somePoint {
  3. case (0, 0):
  4. print("\(somePoint) is at the origin")
  5. case (_, 0):
  6. print("\(somePoint) is on the x-axis")
  7. case (0, _):
  8. print("\(somePoint) is on the y-axis")
  9. case (-2...2, -2...2):
  10. print("\(somePoint) is inside the box")
  11. default:
  12. print("\(somePoint) is outside of the box")
  13. }
  14. // Prints "(1, 1) is inside the box"
../_images/coordinateGraphSimple_2x.png

switch语句确定该点是在原点(0,0)上,在红色x轴上,在橙色y轴上,在以原点为中心的蓝色4 x 4框内还是在框外。

与C不同,Swift允许多种switch情况考虑相同的一个或多个值。实际上,在此示例中,点(0,0)可以匹配所有四种情况。但是,如果可能有多个匹配项,则始终使用第一个匹配情况。点(0,0)将首先匹配,因此所有其他匹配情况将被忽略。case (0, 0)

价值绑定

一个switch情况下,可以将其命名为临时常量或变量,在案件的身体使用相匹配的一个或多个值。这种行为称为值绑定,因为值绑定到案例主体内的临时常量或变量。

下面的示例获取一个(x,y)点,表示为type的元组,并将其分类在下面的图上:(Int, Int)

  1. let anotherPoint = (2, 0)
  2. switch anotherPoint {
  3. case (let x, 0):
  4. print("on the x-axis with an x value of \(x)")
  5. case (0, let y):
  6. print("on the y-axis with a y value of \(y)")
  7. case let (x, y):
  8. print("somewhere else at (\(x), \(y))")
  9. }
  10. // Prints "on the x-axis with an x value of 2"
../_images/coordinateGraphMedium_2x.png

switch语句确定该点是在红色的x轴上,在橙色的y轴上还是在其他位置(都不在两个轴上)。

这3种switch情况声明了占位符常量xy,它们临时取自的一个或两个元组值anotherPoint第一种情况匹配任何值为的点,并将该点的分配给临时常量类似地,第二种情况匹配任何值为的点,并将该点的分配给临时常量case (let x, 0)y0xxcase (0, let y)x0yy

声明临时常量后,可以在案例的代码块中使用它们。在这里,它们用于打印点的分类。

switch句话没有default理由。最后一种情况,声明了两个可以匹配任何值的占位符常量的元组。因为始终是两个值的元组,所以该情况与所有可能的剩余值匹配,并且不需要使情况穷举的情况。case let (x, y)anotherPointdefaultswitch

在哪里

一个switch情况下可以使用where子句来检查附加条件。

下面的示例在下图上对(x,y)点进行了分类:

  1. let yetAnotherPoint = (1, -1)
  2. switch yetAnotherPoint {
  3. case let (x, y) where x == y:
  4. print("(\(x), \(y)) is on the line x == y")
  5. case let (x, y) where x == -y:
  6. print("(\(x), \(y)) is on the line x == -y")
  7. case let (x, y):
  8. print("(\(x), \(y)) is just some arbitrary point")
  9. }
  10. // Prints "(1, -1) is on the line x == -y"
../_images/coordinateGraphComplex_2x.png

switch语句确定该点是在绿色对角线上(),在紫色对角线上()还是都不在。== y== -y

这3种switch情况声明了占位符常量xy,它们暂时占据了来自的两个元组值yetAnotherPoint这些常量用作where子句的一部分,以创建动态过滤器。switch案件的当前值相匹配point只有在where条款的条件计算为true该值。

与前面的示例一样,最终大小写与所有可能的剩余值匹配,因此default不需要使用大小写来使switch语句穷举。

复合案例

可以通过在之后编写多个模式来组合共享同一主体的多个开关盒case,并在每个模式之间使用逗号。如果任何模式都匹配,则认为大小写匹配。如果列表很长,可以将模式写在多行上。例如:

  1. let someCharacter: Character = "e"
  2. switch someCharacter {
  3. case "a", "e", "i", "o", "u":
  4. print("\(someCharacter) is a vowel")
  5. case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
  6. "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
  7. print("\(someCharacter) is a consonant")
  8. default:
  9. print("\(someCharacter) isn't a vowel or a consonant")
  10. }
  11. // Prints "e is a vowel"

switch声明的首字母大写与英语中的所有五个小写元音匹配。同样,它的第二种情况与所有小写的英语辅音匹配。最后,default大小写匹配任何其他字符。

复合案例还可以包括值绑定。复合案例的所有模式都必须包含相同的值绑定集,并且每个绑定都必须从复合案例中的所有模式中获取相同类型的值。这样可以确保,无论复合案例的哪一部分匹配,案例主体中的代码始终可以访问绑定的值,并且该值始终具有相同的类型。

  1. let stillAnotherPoint = (9, 0)
  2. switch stillAnotherPoint {
  3. case (let distance, 0), (0, let distance):
  4. print("On an axis, \(distance) from the origin")
  5. default:
  6. print("Not on an axis")
  7. }
  8. // Prints "On an axis, 9 from the origin"

case上面有两个模式:在x轴和火柴点上的y轴的匹配点。这两种模式都包含for的绑定,并且在这两种模式中都是整数,这意味着in主体中的代码始终可以访问for的值(let distance, 0)(0, let distance)distancedistancecasedistance

控制转移对帐单

通过将控制权从一个代码段转移到另一个代码段,控制转移语句改变了代码执行的顺序。Swift有五个控制转移语句:

  • continue
  • break
  • fallthrough
  • return
  • throw

continuebreakfallthrough语句描述如下。return语句在“函数中进行了描述,而该throw语句在“使用投掷函数传播错误”中进行了描述

继续

continue语句告诉循环停止正在执行的操作,并在循环的下一次迭代开始时重新开始。它说“我已经完成了当前的循环迭代”,而没有完全离开循环。

下面的示例从小写字符串中删除所有元音和空格,以创建一个神秘的难题短语:

  1. let puzzleInput = "great minds think alike"
  2. var puzzleOutput = ""
  3. let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
  4. for character in puzzleInput {
  5. if charactersToRemove.contains(character) {
  6. continue
  7. }
  8. puzzleOutput.append(character)
  9. }
  10. print(puzzleOutput)
  11. // Prints "grtmndsthnklk"

上面的代码continue在与元音或空格匹配时会调用关键字,从而导致循环的当前迭代立即结束并直接跳至下一个迭代的开始。

休息

break语句立即结束整个控制流语句的执行。break语句可以内部使用switch或循环语句,当你要终止的执行switch早于否则会出现这种情况或循环语句。

中断循环语句

在循环语句中使用时,break立即结束循环的执行,并在循环的右括号(}之后将控制权转移到代码不会执行循环的当前迭代中的其他代码,也不会启动循环的其他迭代。

中断切换语句

switch语句中使用时,将break导致该switch语句立即结束其执行,并在该switch语句的右花括号(}之后将控制权转移给代码

此行为可用于匹配和忽略switch语句中的一个或多个情况由于Swift的switch陈述是详尽无遗的,并且不允许有空的案例,因此有时有必要故意匹配并忽略案例以使您的意图明确。通过将break语句编写为要忽略的案例的整体来完成此操作当该案例与该switch语句匹配时,该案例break内的switch语句将立即终止该语句的执行。

笔记

一个switch仅包含注释的情况下被报告为编译时错误。注释不是陈述,也不会使switch案例被忽略。始终使用break语句忽略switch大小写。

下面的示例打开一个Character值,并确定它是否代表四种语言之一的数字符号。为简便起见,在一个switch案例中涵盖了多个值

  1. let numberSymbol: Character = "三" // Chinese symbol for the number 3
  2. var possibleIntegerValue: Int?
  3. switch numberSymbol {
  4. case "1", "١", "一", "๑":
  5. possibleIntegerValue = 1
  6. case "2", "٢", "二", "๒":
  7. possibleIntegerValue = 2
  8. case "3", "٣", "三", "๓":
  9. possibleIntegerValue = 3
  10. case "4", "٤", "四", "๔":
  11. possibleIntegerValue = 4
  12. default:
  13. break
  14. }
  15. if let integerValue = possibleIntegerValue {
  16. print("The integer value of \(numberSymbol) is \(integerValue).")
  17. } else {
  18. print("An integer value couldn't be found for \(numberSymbol).")
  19. }
  20. // Prints "The integer value of 三 is 3."

这个例子检查numberSymbol,以确定它是否为数字的拉丁语,阿拉伯语,中国,泰国或符号14如果找到匹配项,则该switch语句的一种情况将一个可选Int?变量possibleIntegerValue设置为适当的整数值。

在之后switch的语句执行完成后,该示例使用可选的绑定,来确定一个值是否被发现。由于possibleIntegerValue变量nil是一个可选类型,因此它具有一个隐式初始值,因此,仅当possibleIntegerValueswitch语句的前四种情况之一将其设置为实际值时,该可选绑定才会成功

由于Character在上面的示例中列出每个可能的并不切实际,因此default大小写可处理所有不匹配的字符。这种default情况不需要执行任何操作,因此它以单个break语句作为主体来编写一旦default情况匹配时,break语句结束switch语句的执行,并执行代码从继续发言。if let

跌倒

在Swift中,switch语句不会落入每种情况的底部,而不会落入下一种情况。也就是说,switch第一个匹配的案例完成后,整个语句就完成了其执行。相比之下,C要求您break在每种switch情况的末尾插入一个显式语句,以防止失败。避免默认失败会导致Swiftswitch语句比C语言中的对应语句更加简洁和可预测,因此避免switch了错误地执行多个情况。

如果您需要C风格的失败行为,则可以根据具体情况选择使用fallthrough关键字来启用此行为下面的示例fallthrough用于创建数字的文字说明。

  1. let integerToDescribe = 5
  2. var description = "The number \(integerToDescribe) is"
  3. switch integerToDescribe {
  4. case 2, 3, 5, 7, 11, 13, 17, 19:
  5. description += " a prime number, and also"
  6. fallthrough
  7. default:
  8. description += " an integer."
  9. }
  10. print(description)
  11. // Prints "The number 5 is a prime number, and also an integer."

本示例声明一个String名为的新变量,description并为其分配一个初始值。然后,该函数考虑integerToDescribe使用switch语句的价值如果的值integerToDescribe是列表中的质数之一,则该函数会将文本追加到的末尾description,以注意该数字是质数。然后,它也使用fallthrough关键字来“落入”default案件。default案例在说明的末尾添加了一些额外的文本,并且该switch语句已完成。

除非的值integerToDescribe在已知质数列表中,否则第一种switch情况根本不匹配因为没有其他特定情况,integerToDescribe所以要按情况进行匹配default

在之后switch的语句执行完毕,数量的描述是使用打印print(_:separator:terminator:)功能。在此示例中,该数字5被正确标识为素数。

笔记

fallthrough关键字不检查的情况下条件,switch它使执行陷入如此。fallthrough关键字简单地使代码执行直接移动到下一个的情况下(或内的语句default的情况下)嵌段,在C的标准switch语句的行为。

带标签的声明

在Swift中,您可以将循环和条件语句嵌套在其他循环和条件语句中,以创建复杂的控制流结构。但是,循环和条件语句都可以使用该break语句过早地结束其执行。因此,有时对于明确break声明要终止的循环或条件语句很有用同样,如果您有多个嵌套循环,则明确continue声明语句应该影响哪个循环会很有用

为了实现这些目标,可以使用语句标签标记循环语句或条件语句对于条件语句,可以将语句标签与该break语句一起使用以结束带标签的语句的执行。对于循环语句,可以将语句标签与breakcontinue语句一起使用以结束或继续执行带标签的语句。

通过将标签放置在与该语句的介绍者关键字相同的行上,然后加上冒号,可以指示已标记的语句。这是while循环的这种语法示例,尽管原理对于所有循环和switch语句都是相同的

  1. label name: while condition {
  2. statements
  3. }

下面的示例将带有标记循环breakandcontinue语句while用于本章前面介绍Snakes and Ladders游戏的改编版本这次,游戏有一个额外的规则:

  • 为了赢球,您必须准确落在25号广场上。

如果特定骰子掷骰将使您超出25号方格,则必须再次掷骰,直到您掷出准确的数字才能落在25号方格上。

游戏板与以前相同。

../_images/snakesAndLadders_2x.png

的值finalSquareboardsquare,并diceRoll以同样的方式为前初始化:

  1. let finalSquare = 25
  2. var board = [Int](repeating: 0, count: finalSquare + 1)
  3. board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
  4. board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
  5. var square = 0
  6. var diceRoll = 0

此版本的游戏使用while循环和switch语句来实现游戏的逻辑。while循环有一个语句标签,称为gameLoop,它指示它是Snakes and Ladders游戏的主要游戏循环。

while循环的条件为,以反映您必须准确降落在广场25。while square != finalSquare

  1. gameLoop: while square != finalSquare {
  2. diceRoll += 1
  3. if diceRoll == 7 { diceRoll = 1 }
  4. switch square + diceRoll {
  5. case finalSquare:
  6. // diceRoll will move us to the final square, so the game is over
  7. break gameLoop
  8. case let newSquare where newSquare > finalSquare:
  9. // diceRoll will move us beyond the final square, so roll again
  10. continue gameLoop
  11. default:
  12. // this is a valid move, so find out its effect
  13. square += diceRoll
  14. square += board[square]
  15. }
  16. }
  17. print("Game over!")

在每个循环的开始掷骰子。循环不是立即移动玩家,而是使用一条switch语句来考虑移动的结果并确定是否允许移动:

  • 如果掷骰子将玩家移至最后一个方块,则游戏结束。语句将控制权转移到循环外部的第一行代码,从而结束了游戏。break gameLoopwhile
  • 如果骰子掷出将移动玩家超越最后的广场,此举是无效的,玩家需要再次卷。语句结束当前循环迭代,并开始循环的下一个迭代。continue gameLoopwhile
  • 在所有其他情况下,掷骰子都是有效的举动。玩家向前移动diceRoll正方形,游戏逻辑检查是否有蛇和梯子。然后循环结束,控制返回到while条件以确定是否需要再转一圈。

笔记

如果break上面语句不使用gameLoop标签,它将脱离该switch语句,而不是该while语句。使用gameLoop标签可以清楚地表明哪个控制语句应该终止。

gameLoop调用跳转到循环的下一个迭代时,不一定必须使用标签游戏中只有一个循环,因此对于该语句将影响哪个循环没有任何歧义但是,将标签与语句一起使用不会有任何危害这样做与标签在声明中的用法一致,并有助于使游戏的逻辑更易于阅读和理解。continue gameLoopcontinuegameLoopcontinuebreak

提前退出

guard语句,像一个if语句,执行根据表达式的布尔值的语句。您使用一条guard语句要求条件必须为true,以便guard执行语句后的代码if语句不同guard语句始终具有一个else子句-else如果条件不成立,则执行子句中的代码

  1. func greet(person: [String: String]) {
  2. guard let name = person["name"] else {
  3. return
  4. }
  5. print("Hello \(name)!")
  6. guard let location = person["location"] else {
  7. print("I hope the weather is nice near you.")
  8. return
  9. }
  10. print("I hope the weather is nice in \(location).")
  11. }
  12. greet(person: ["name": "John"])
  13. // Prints "Hello John!"
  14. // Prints "I hope the weather is nice near you."
  15. greet(person: ["name": "Jane", "location": "Cupertino"])
  16. // Prints "Hello Jane!"
  17. // Prints "I hope the weather is nice in Cupertino."

如果guard满足语句的条件,则在该guard语句的右大括号之后继续执行代码使用guard语句中的可选绑定为条件分配值的任何变量或常量都可用于该语句所在的其余代码块

如果不满足该条件,else则执行分支内的代码该分支必须转移控制权以退出该guard语句所在的代码块它可以控制转移语句做到这一点,例如returnbreakcontinue,或者throw,也可以调用一个函数或方法不返回,如fatalError(_:file:line:)

guard与对if语句进行相同的检查相比,针对需求使用语句可以提高代码的可读性它使您可以编写通常执行的代码而无需将其包装在一个else块中,并且可以将处理违反要求的代码保留在要求旁边。

检查API可用性

Swift具有检查API可用性的内置支持,可确保您不会意外使用给定部署目标上不可用的API。

编译器使用SDK中的可用性信息来验证代码中使用的所有API在项目指定的部署目标上是否可用。如果您尝试使用不可用的API,则Swift会在编译时报告错误。

语句中使用可用性条件来有条件地执行代码块,具体取决于要使用的API在运行时是否可用。当编译器验证该代码块中的API可用时,将使用可用性条件中的信息。ifguard

  1. if #available(iOS 10, macOS 10.12, *) {
  2. // Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
  3. } else {
  4. // Fall back to earlier iOS and macOS APIs
  5. }

上面的可用性条件指定在iOS中,该if语句的主体仅在iOS 10及更高版本中执行;否则,该语句的主体仅在iOS 10和更高版本中执行。在macOS中,仅在macOS 10.12及更高版本中。最后一个参数,*是必需的,它指定在任何其他平台上,if执行程序的主体将在目标所指定的最小部署目标上执行。

在一般情况下,可用性条件采用平台名称和版本的列表。您可以使用平台的名称,如iOSmacOSwatchOS,和tvOS-对于完整列表,请参阅声明属性除了指定主要版本号(例如iOS 8或macOS 10.10)之外,您还可以指定次要版本号(例如iOS 11.2.6和macOS 10.13.3)。

  1. if #available(platform name version, ..., *) {
  2. statements to execute if the APIs are available
  3. } else {
  4. fallback statements to execute if the APIs are unavailable
  5. }

 

 
posted @ 2018-09-29 20:01  为敢技术  阅读(618)  评论(0编辑  收藏  举报