➽04流程控制

Posted itzyjr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了➽04流程控制相关的知识,希望对你有一定的参考价值。

for-in循环
迭代数组:

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

迭代Dictionary:

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

Dictionary的内容本质上是无序的,对它们进行迭代并不能保证检索它们的顺序。特别是,在Dictionary中插入项的顺序并不定义它们的迭代顺序。

按范围迭代:

for index in 1...5 {
    print("\\(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
}
print("\\(base) to the power of \\(power) is \\(answer)")
// Prints "3 to the power of 10 is 59049"

在某些情况下,您可能不希望使用包含两个端点的闭合范围。考虑在手表表面上画每分钟的刻度标记。您想从0分钟开始画60个记号。使用半开范围运算符(…<)包括下限,但不包括上限。

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

一些用户可能希望他们的UI中的记号更少。他们可以选择每5分钟一次。使用stride(from:to:by)功能跳过不需要的标记。

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

通过使用stride(from:through:by:),也可以使用闭合范围:

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

上面的示例使用for-in循环来迭代范围、数组、字典和字符串。但是,您可以使用此语法迭代任何集合,包括您自己的类和集合类型,只要这些类型符合Sequence协议。

while循环
Swift提供两种while循环:
while在循环的每次传递开始时评估其条件。
repeat-while在循环的每次传递结束时评估其条件。

介绍个游戏——蛇与梯子

玩法:从横盘外开始,通过掷骰子,沿虚线方向前进骰子的点数步,遇到梯子就上梯子,遇到蛇头就滑到蛇尾,最先到达横盘右上角或超出的获胜。

因为玩家从棋盘开始,在“零块格子”上,棋盘被初始化为26个0整数值,而不是25个:

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

使梯子与蛇发挥作用:

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 {
    // roll the dice
    diceRoll += 1
    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]
    }
}
print("Game over!")

repeat-while循环
它与其他语言中的do-while循环是相似的。即,先执行repeat{}代码块,不用考虑循环条件。
格式如下:

repeat {
    statements
} while condition

条件语句if

temperatureInFahrenheit = 90
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.")
} else {
    print("It's not that cold. Wear a t-shirt.")
}
// Prints "It's really warm. Don't forget to wear sunscreen."

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
}
let someCharacter: Character = "z"
switch someCharacter {
case "a":
    print("The first letter of the alphabet")
case "z":
    print("The last letter of the alphabet")
default:
    print("Some other character")
}
// Prints "The last letter of the alphabet"

Swift中的switch语句不会贯穿每个case的底部,所以不需要像其他语言一样需要break语句。

尽管Swift中不需要break,但你可以使用break语句匹配并忽略特定case,或者在case完成执行之前中断匹配case。

每个case的主体必须至少包含一条可执行语句!

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // 无效! the case has an empty body
case "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// This will report a compile-time error.

同时匹配多个值,用逗号分隔:

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":// 复合case
    print("The letter A")
default:
    print("Not the letter A")
}
// Prints "The letter A"

为了便于阅读,复合case也可以写在多行上。

如果要在特定的switch case结尾处显式地落空(fall through),请使用fallthrough关键字。

区间匹配

let approximateCount = 62
let countedThings = "moons orbiting Saturn"
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("There are \\(naturalCount) \\(countedThings).")
// Prints "There are dozens of moons orbiting Saturn."

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

下面的示例采用一个(x, y)点,表示为(Int, Int)类型的简单元组,根据下图对点进行分类。

let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    print("\\(somePoint) is at the origin")
case (_, 0):
    print("\\(somePoint) is on the x-axis")
case (0, _):
    print("\\(somePoint) is on the y-axis")
case (-2...2, -2...2):
    print("\\(somePoint) is inside the box")
default:
    print("\\(somePoint) is outside of the box")
}
// Prints "(1, 1) is inside the box"

值绑定
一个switch case可以给匹配的临时常量或变量命名值(一个或多个值),以便在case体中使用。这种行为称为值绑定(value binding),因为值绑定到case体中的临时常量或变量。

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))")
}
// Prints "on the x-axis with an x value of 2"

上面case (let x, 0):,其中的(let x, 0)即是case体,x是临时常量,case体与(2, 0)匹配,这样就有let x = 2,即:“switch case给匹配的临时常量x命名值为2”。

第一个case:case(let x, 0),它匹配y值为0的任何点,并将该点的x值指定给临时常量x。声明临时常量后,可以在case的代码块中使用它们。
此switch语句没有default。最后一个case:case let (x, y)声明了一个包含两个占位符常量的元组,可以匹配任何值。因为anotherPoint始终是两个值的元组,所以这种情况匹配所有可能的剩余值,并且不需要使用默认情况来使switch语句穷尽。

where
一个switch 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")
}
// Prints "(1, -1) is on the line x == -y"

仅当where子句的条件对该值的计算结果为true时,switch case才与point的当前值匹配。

复合case

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) isn't a vowel or a consonant")
}
// Prints "e is a vowel"

复合case还可以包括值绑定:

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")
}
// Prints "On an axis, 9 from the origin"

控制转移语句
continue
continue语句告诉循环停止它正在做的事情,并在循环的下一次迭代开始时重新开始。

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

let puzzleInput = "great minds think alike"
var puzzleOutput = ""
let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
for character in puzzleInput {
    if charactersToRemove.contains(character) {
        continue
    }
    puzzleOutput.append(character)
}
print(puzzleOutput)
// Prints "grtmndsthnklk"

break
break语句立即结束整个控制流语句的执行。当你希望提前终止switch或loop语句的执行时,可以在switch或loop语句中使用break语句。

let numberSymbol: Character = "三"  // Chinese symbol for the number 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 {// possibleIntegerValue设置为了实际值,可选绑定成功
    print("The integer value of \\(numberSymbol) is \\(integerValue).")
} else {
    print("An integer value couldn't be found for \\(numberSymbol).")
}
// Prints "The integer value of 三 is 3."

本例检查numberSymbol以确定数字1到4是拉丁、阿拉伯语、汉语还是泰语符号。如果找到匹配项,switch语句的一个case将设置可选的Int?将名为possibleIntegerValue的变量设置为适当的整数值。

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

如果去掉var possibleIntegerValue: Int?语句中的问号?,则这行语句if let integerValue = possibleIntegerValue {直接检查报错:Initializer for conditional binding must have Optional type, not 'Int'

因为在上面的示例中列出所有可能的字符值是不现实的,所以default会处理任何不匹配的字符。这个默认情况不需要执行任何操作,因此它的主体是一个break语句。一旦匹配了默认情况,break语句就会结束switch语句的执行,并且代码执行将从if let语句继续。

fallthrough
在Swift中,switch语句不会从每个case的底部进入下一个case。也就是说,第一个匹配的case一完成,整个switch语句就完成了执行。相反,C要求您在每个case情况的末尾插入一个显式的break语句,以防止出错。避免缺省故障意味着Swift switch语句比C中的对应语句更简洁、更可预测,因此它们避免了错误地执行多个switch用例。

如果你需要C风格的fallthrough行为,可以使用fallthrough关键字。
下面的示例使用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)
// Prints "The number 5 is a prime number, and also an integer."

标记语句
在Swift中,可以在其他循环和条件语句中嵌套循环和条件语句,以创建复杂的控制流结构。但是,循环和条件语句都可以使用break语句提前结束它们的执行。因此,有时明确表示希望break语句终止的循环或条件语句非常有用。类似地,如果您有多个嵌套循环,那么明确continue语句应该影响哪个循环会很有用。

为了达到这些目的,可以使用语句标签标记循环语句或条件语句。对于条件语句,可以将语句标签与break语句一起使用,以结束已标记语句的执行。对于循环语句,可以将语句标签与break或continue语句一起使用,以结束或继续执行已标记语句。

格式如下:

label_name: while condition {
    statements
}
gameLoop: while square != finalSquare {
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    switch square + diceRoll {
    case finalSquare:
        // diceRoll will move us to the final square, so the game is over
        break gameLoop// break外层循环
    case let newSquare where newSquare > finalSquare:
        // diceRoll will move us beyond the final square, so roll again
        continue gameLoop// continue外层循环
    default:
        // this is a valid move, so find out its effect
        square += diceRoll
        square += board[square]
    }
}
print("Game over!")

提前退出
与if语句类似,guard语句根据表达式的布尔值执行语句。你使用guard语句来要求条件必须为true才能执行guard语句后的代码。与if语句不同,guard语句总是有一个else子句。如果条件不为true,则执行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(person: ["name": "John"])
// Prints "Hello John!"
// Prints "I hope the weather is nice near you."
greet(person: ["name": "Jane", "location": "Cupertino"])
// Prints "Hello Jane!"
// Prints "I hope the weather is nice in Cupertino."

如果不满足该条件,则执行else分支中的代码。该分支必须转移控制才能退出出现guard语句的代码块。它可以通过诸如return、break、continue或throw之类的控制传输语句来实现这一点,也可以调用不返回的函数或方法,例如fatalError(_:file:line:)
与使用if语句进行相同的检查相比,对需求使用guard语句可以提高代码的可读性。它允许您编写通常执行的代码,而无需将其包装在else块中,并且允许您将处理违反的需求的代码保留在需求旁边。

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

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

根据要使用的API在运行时是否可用,可以在if或guard语句中使用可用性条件有条件地执行代码块。编译器在验证该代码块中的API是否可用时,使用可用性条件中的信息。

if #available(ios 10, macOS 10.12, *) {
    // Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
} else {
    // Fall back to earlier iOS and macOS APIs
}

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

在其一般形式中,可用性条件采用平台名称和版本的列表。完整列表使用iOS、macOS、watchOS和tvOS等平台名称,请参见Declaration Attributes。除了指定主要版本号(如iOS 8或macOS 10.10)外,还可以指定次要版本号(如iOS 11.2.6和macOS 10.13.3)。

格式如下:

if #available(platform_name version, ..., *) {
    statements to execute if the APIs are available
} else {
    fallback statements to execute if the APIs are unavailable
}

以上是关于➽04流程控制的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段——git命令操作一个完整流程

周一04.2流程控制if……else

python基础 -- 04流程控制语句

VSCode自定义代码片段15——git命令操作一个完整流程

VSCode自定义代码片段15——git命令操作一个完整流程

java-04流程控制语句