Swift 中的控制流与函数详解
1. switch 语句
switch 语句会获取一个值,然后将其与多个可能的匹配项进行比较,并根据第一个成功的匹配执行相应的代码块。它是在有多个可能匹配项时替代 if - else 语句的一种选择。其格式如下:
switch value {
case match1 :
block of code
case match2 :
block of code
…… as many cases as needed
default :
block of code
}
与大多数其他语言中的 switch 语句不同,在 Swift 中,它不会贯穿到下一个 case 语句,因此不需要使用 break 语句来防止贯穿。这是 Swift 内置的一项安全特性,因为初学者在使用 switch 语句时最常见的编程错误之一就是忘记在 case 语句末尾添加 break 语句。
以下是一个使用 switch 语句的示例:
var speed = 300000000
switch speed {
case 300000000:
print("Speed of light")
case 340:
print("Speed of sound")
default:
print("Unknown speed")
}
在上述示例中,switch 语句获取 speed 变量的值,并将其与两个 case 语句进行比较。如果 speed 的值与任何一个 case 匹配,它将输出该速度的信息。如果没有找到匹配项,则输出 “Unknown speed” 消息。
每个 switch 语句必须涵盖所有可能的值。这意味着除非是与枚举进行匹配,否则每个 switch 语句都必须有一个 default case。例如:
var num = 5
switch num {
case 1 :
print("number is one")
case 2 :
print("Number is two")
case 3 :
print("Number is three")
}
如果将上述代码放入 Playground 并尝试编译,会收到 “switch must be exhaustive, consider adding a default clause” 错误。这是一个编译时错误,只有在尝试编译代码时才会被通知。
可以在单个 case 中包含多个项目,只需用逗号分隔这些项目即可。例如,判断一个字符是元音还是辅音:
var char : Character = "e"
switch char {
case "a", "e", "i", "o", "u":
print("letter 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("letter is a consonant")
default:
print("unknown letter")
}
还可以使用范围运算符来检查 switch 语句的值是否包含在某个范围内。例如:
var grade = 93
switch grade {
case 90...100:
print("Grade is an A")
case 80...89:
print("Grade is a B")
case 70...79:
print("Grade is an C")
case 60...69:
print("Grade is a D")
case 0...59:
print("Grade is a F")
default:
print("Unknown Grade")
}
在 Swift 中,任何 case 语句都可以包含一个可选的 guard 条件,以提供额外的验证条件。guard 条件使用 where 关键字定义。例如:
var studentId = 4
var grade = 57
switch grade {
case 90...100:
print("Grade is an A")
case 80...89:
print("Grade is a B")
case 70...79:
print("Grade is an C")
case 55...69 where studentId == 4:
print("Grade is a D for student 4")
case 60...69:
print("Grade is a D")
case 0...59:
print("Grade is a F")
default:
print("Unknown Grade")
}
需要注意的是,Swift 会从第一个 case 语句开始按顺序检查每个 case 语句。因此,如果将带有 guard 表达式的 case 语句放在 “Grade is a F” case 语句之后,那么带有 guard 表达式的 case 语句将永远不会被执行。
switch 语句在评估枚举时也非常有用。由于枚举的值是有限的,如果为枚举的所有值提供了 case 语句,则不需要提供 default case。例如:
enum Product {
case Book(String, Double, Int)
case Puzzle(String, Double)
}
var order = Product.Book("Mastering Swift 2", 49.99, 2015)
switch order {
case .Book(let name, let price, let year):
print("You ordered the book \(name) for \(price)")
case .Puzzle(let name, let price):
print("You ordered the Puzzle \(name) for \(price)")
}
2. 在条件语句中使用 case 和 where 语句
从 Swift 2 开始,可以在 if、for 和 while 等其他条件语句中使用 case 和 where 语句。在条件语句中使用这些语句可以使代码更简洁、易读。
2.1 使用 where 语句过滤 for - in 循环的结果
在不使用 where 语句过滤偶数的示例:
for number in 1…30 {
if number % 2 == 0 {
print(number)
}
}
使用 where 语句过滤偶数的示例:
for number in 1...30 where number % 2 == 0 {
print(number)
}
使用 where 语句可以减少代码行数,并且由于过滤语句与 for - in 循环在同一行,使代码更易读。
2.2 使用 for - case 语句进行过滤
以下是使用 for - case 语句过滤数组中特定元素的示例:
var worldSeriesWinners = [
("Red Sox", 2004),
("White Sox", 2005),
("Cardinals", 2006),
("Red Sox", 2007),
("Phillies", 2008),
("Yankees", 2009),
("Giants", 2010),
("Cardinals", 2011),
("Giants", 2012),
("Red Sox", 2013),
("Giants", 2014)
]
for case let ("Red Sox", year) in worldSeriesWinners {
print(year)
}
该示例中,创建了一个包含元组的数组 worldSeriesWinners,每个元组包含球队名称和获胜年份。使用 for - case 语句过滤出 “Red Sox” 获胜的年份并输出。
for - case 语句还可以轻松过滤可选数组中的 nil 值。例如:
let myNumbers: [Int?] = [1, 2, nil, 4, 5, nil, 6]
for case let .Some(num) in myNumbers {
print(num)
}
也可以将 for - case 与 where 语句结合使用进行额外过滤:
let myNumbers: [Int?] = [1, 2, nil, 4, 5, nil, 6]
for case let num? in myNumbers where num > 3 {
print(num)
}
如果不使用 case 和 where 语句进行相同的过滤,代码如下:
for num in myNumbers {
if let num = num {
if num > 3 {
print(num)
}
}
}
可以看出,使用 for - case 和 where 语句可以大大减少所需的代码行数,并且使代码更易读。
2.3 使用 if - case 语句
if - case 语句与 switch 语句非常相似。大多数情况下,更倾向于使用 switch 语句,但在只寻找一两个可能匹配项且不想处理所有可能匹配项时,if - case 语句更合适。例如:
enum Identifier {
case Name(String)
case Number(Int)
case NoIdentifier
}
var playerIdentifier = Identifier.Number(42)
if case let .Number(num) = playerIdentifier {
print("Player's number is \(num)")
}
同样,可以在 if - case 语句中使用 where 语句进行额外过滤:
var playerIdentifier = Identifier.Number(42)
if case let .Number(num) = playerIdentifier where num == 2 {
print("Player is either Xander Bogarts or Derek Jeter")
}
3. 控制转移语句
Swift 提供了五种控制转移语句:continue、break、fallthrough、guard、throws 和 return。
3.1 continue 语句
continue 语句告诉循环停止执行当前代码块,并进入循环的下一次迭代。以下是一个使用 continue 语句打印范围内奇数的示例:
for i in 1...10 {
if i % 2 == 0 {
continue
}
print("\(i) is odd")
}
输出结果为:
1 is odd
3 is odd
5 is odd
7 is odd
9 is odd
3.2 break 语句
break 语句会立即结束控制流中代码块的执行。以下是一个在遇到第一个偶数时跳出 for 循环的示例:
for i in 1...10 {
if i % 2 == 0 {
break
}
print("\(i) is odd")
}
输出结果为:
1 is odd
3.3 fallthrough 语句
在 Swift 中,switch 语句不会贯穿到下一个 case 语句,但可以使用 fallthrough 语句强制贯穿。fallthrough 语句可能很危险,因为一旦找到匹配项,下一个 case 默认会被执行。例如:
var name = "Jon"
var sport = "Baseball"
switch sport {
case "Baseball":
print("\(name) plays Baseball")
fallthrough
case "Basketball":
print("\(name) plays Basketball")
fallthrough
default:
print("Unknown sport")
}
输出结果为:
Jon plays Baseball
Jon plays Basketball
Unknown sport
3.4 guard 语句
在 Swift 2 中,Apple 引入了新的 guard 语句。它专注于在条件为 false 时执行某个功能,允许在函数早期捕获错误并执行错误处理。例如:
var x = 9
guard x > 10 else {
// Do error condition
return
}
// Functional code here
在上述示例中,检查变量 x 是否大于 10,如果不大于 10,则执行错误处理。如果 x 大于 10,代码继续执行。guard 语句中的代码必须包含一个控制转移语句,以防止其余代码执行。如果忘记添加控制转移语句,Swift 会显示编译时错误。
综上所述,Swift 中的控制流和函数提供了丰富的功能和灵活的语法,能够帮助开发者编写更安全、简洁和易读的代码。通过合理使用 switch 语句、case 和 where 语句以及控制转移语句,可以更好地处理各种情况和错误,提高代码的质量和可维护性。
Swift 中的控制流与函数详解(下半部分)
4. 控制流与函数的综合应用示例
为了更好地理解上述控制流和函数相关知识的实际应用,下面给出一些综合示例。
4.1 综合使用 switch 和 where 进行复杂条件判断
假设我们要根据学生的成绩和是否为特殊学生来给出不同的评价。代码如下:
enum StudentType {
case Normal
case Special
}
var studentType = StudentType.Special
var grade = 57
var studentId = 4
switch grade {
case 90...100:
print("Excellent performance!")
case 80...89:
print("Good job!")
case 70...79:
print("Not bad, keep it up!")
case 55...69 where studentType == .Special && studentId == 4:
print("For special student 4, this is still a passable grade.")
case 60...69:
print("You passed, but there is room for improvement.")
case 0...59:
print("Need to work harder.")
default:
print("Unknown grade.")
}
在这个示例中,我们结合了枚举类型
StudentType
来区分普通学生和特殊学生,并且在 switch 语句中使用了
where
子句来对特殊学生的成绩进行额外判断。
4.2 结合 for - case 和 guard 进行数组元素处理
假设有一个包含可选整数的数组,我们要找出其中大于 5 且不为
nil
的元素,并对其进行一些操作。代码如下:
let myNumbers: [Int?] = [1, nil, 6, 3, nil, 8, 2]
for case let num? in myNumbers {
guard num > 5 else {
continue
}
print("The number \(num) meets the requirement.")
}
这里我们先使用
for - case
过滤掉
nil
值,然后使用
guard
语句进一步筛选出大于 5 的元素。
5. 控制流语句的性能考虑
在使用控制流语句时,性能也是一个需要考虑的因素。以下是一些常见控制流语句的性能特点:
| 控制流语句 | 性能特点 |
|---|---|
| switch |
当有多个离散值需要匹配时,
switch
语句的性能通常较好,尤其是在枚举类型的匹配上。因为编译器可以对枚举类型的
switch
进行优化,直接跳转到匹配的
case
分支。
|
| if - else |
对于简单的条件判断,
if - else
语句的性能是可以接受的。但如果有多个嵌套的
if - else
语句,会增加代码的复杂度和执行时间。
|
| for - in |
for - in
循环在遍历数组、集合等序列时性能较好,因为它是按照顺序依次访问元素。但如果在循环体中进行复杂的操作,会影响整体性能。
|
| while |
while
循环的性能取决于循环条件的判断和循环体的执行时间。如果循环条件判断复杂或者循环体执行时间长,会导致性能下降。
|
6. 最佳实践建议
为了编写高质量的 Swift 代码,在使用控制流和函数时,可以遵循以下最佳实践:
6.1 switch 语句
-
确保
switch语句覆盖所有可能的值,除非是对枚举类型进行匹配且已经为所有枚举值提供了case分支。 -
当使用
guard表达式时,将带有guard条件的case语句放在没有guard条件的类似case语句之前。 -
在枚举类型的
switch中,尽量避免使用default分支,除非确实有未处理的情况。
6.2 case 和 where 语句
-
在条件语句中使用
case和where语句可以使代码更简洁、易读,尤其是在过滤和匹配操作中。 -
结合
for - case和where语句可以减少嵌套的if语句,提高代码的可读性。
6.3 控制转移语句
-
continue语句适用于跳过当前循环迭代中不需要执行的代码,提高循环效率。 -
break语句用于提前终止循环或switch语句,避免不必要的计算。 -
fallthrough语句要谨慎使用,因为它可能会导致代码逻辑混乱,除非确实需要强制贯穿。 -
guard语句可以在函数开始时处理错误条件,使函数的主要逻辑更加清晰。
7. 总结
Swift 中的控制流和函数提供了丰富的工具来处理各种编程场景。
switch
语句可以方便地进行多值匹配,
case
和
where
语句可以在条件语句中进行灵活的过滤和匹配,而控制转移语句则可以精确地控制代码的执行流程。
通过合理运用这些控制流和函数的特性,开发者可以编写出更安全、简洁、易读且性能良好的代码。同时,遵循最佳实践建议可以进一步提高代码的质量和可维护性。在实际开发中,要根据具体的需求和场景选择合适的控制流语句和函数,以达到最佳的编程效果。
下面是一个简单的 mermaid 流程图,展示了
for - case
和
where
结合使用的流程:
graph TD;
A[开始] --> B[遍历数组元素];
B --> C{元素是否为非 nil};
C -- 是 --> D{元素是否满足 where 条件};
C -- 否 --> B;
D -- 是 --> E[处理元素];
D -- 否 --> B;
E --> B;
B --> F[结束];
这个流程图清晰地展示了使用
for - case
和
where
语句过滤数组元素的过程。首先遍历数组元素,判断元素是否为非
nil
,如果是则进一步判断是否满足
where
条件,满足则进行处理,不满足则继续遍历下一个元素,直到遍历完所有元素。
111

被折叠的 条评论
为什么被折叠?



