Swift流程控制

336 阅读11分钟

for-in循环

  • 使用for-in循环来遍历序列,比如一个范围的数字,数组中的元素或者字符串中的字符
for i in 0...3 {
print(i)
}
for c in "Hello,World" {
 print(c)
}
let names = ["zhangsan","lisi","wangwu","zhaoliu"]
for name in names {
 print(name)
}

for-in遍历字典

  • 当字典遍历时,每一个元素都返回一个(key,value)元组,你可以在for-in循环体中使用显式命名常量来分解(key,value)元组成员。
let numberOfLegs = ["spider":8,"ant":6,"cat":4]
for (animalName,legCount) in numberOfLegs {
print("\(animalName) has \(legCount) legs")
}

for t in numberOfLegs {
print("\(t.0) has \(t.1) legs")
}
  • 如果不需要序列的每一个值,可以使用下划线取代遍历名忽略值
let base = 3
let power = 5
let answer = 1
for _ in 1...power {
 answer *= base
}
print("\(base) to the power of \(power) is \(answer)")

for-in 分段区间

  • 使用stride(from:to:by)函数来跳过不想要的标记(开区间)
  • 闭区间同样适用,使用stride(from:through:by:)即可
let minuteInterval = 5
for tickMark in stride(from:0,to:50,by:minuteInterval){
print(tickMark)
}
// 输出结果为:
// 0 5 10 15 20 25 30 35 40 45

let minuteInterval = 5
for tickMark in stride(from:0,to:50,by:minuteInterval){
print(tickMark)
}
// 输出结果为:
// 0 5 10 15 20 25 30 35 40 45 50

while循环

  • repeat-while循环(OC do-while)
var count = 0
repeat {
print(count)
count += 1
} while count < 5
// 输出结果为: 0 1 2 3 4

switch

  • switch语句会将一个值与多个可能得模式匹配。然后基于第一个成功匹配的模式来执行合适的代码块。
  • switch语句一定得是全面的。就是说,给定类型里每一个值都得被考虑到并且匹配到一个switch的case。如果无法提供一个switch case所有可能得值,你可以定义一个默认匹配所有的case来匹配所有未明确出来的值。这个匹配所有的情况用关键字default标记,并且必须在所有case的最后出现。
  • OC swtich 语句如果不全面,仍然可以运行

没有隐式贯穿

  • 相比C和OC里的switch语句来说,Swift里的switch语句不会默认从匹配case的末尾贯穿到下一个case里。
  • 相反,整个switch语句会在匹配到第一个switch的case执行完毕之后退出,不再需要显式的break语句。
  • 每一个case的函数必须包含至少一个可执行的语句
  • 在一个switch的case中匹配多个值可以用逗号分隔,并且可以写成多行

区间匹配

  • switch的case的值可以在一个区间中匹配

元组匹配

  • 你可以使用元组来在一个switch语句中测试多个值
  • 使用下划线(_)来表明匹配所有可能的值

值绑定

  • switch的case可以将匹配到的值临时绑定为一个常量或者变量,来给case的函数体使用
  • 如果使用var关键字,临时的变量就会以合适的值来创建并初始化。对这个变量的任何改变都只会在case的函数体内有效

image.png

where字句

  • switch case可以使用where分句来检查是否符合特定的约束

image.png

复合匹配

  • 多种情形共享同一个函数体的多个情况可以在case后写多个模式来复合,在每个模式间用逗号分隔。如果任何一个模式匹配了,那么这个情况会被认为是匹配的。如果模式太长,可以把它们写成多行。

image.png

复合匹配-值绑定

  • 复合匹配同样可以包含值绑定。所有复合匹配的模式都必须包含相同的值绑定集合,并且复合情况中的每一个绑定都得有相同的类型格式。这才能确保无论复合匹配的那部分命中了,接下来的函数体中的代码都能访问到绑定的值并且值的类型也都相同。

image.png

控制转移

  • continue
  • break
  • fallthrough
  • return
  • throw

continue

  • continue语句告诉循环停止正在做的事情并且再次从头开始循环的下一次遍历。它是说"不再继续当前的循环遍历了"而不是离开整个的循环。

break

  • break语句会立即结束整个控制流语句。当你想要提前结束switch或者循环语句或者其它情况时可以在switch语句或者循环语句中使用break语句。
  • 挡在循环语句中使用时,break会立即结束循环的执行,并且转移控制到循环结束的花括号(})后的第一行代码上。当前遍历循环的其他代码都不会被执行,并且余下的遍历循环也不会开始了。
  • 当在switch语句里使用时,break导致switch语句立即结束它的执行,并且转移控制到switch语句结束花括号(})之后的第一行代码上。

fallthrough

  • 如果你确实需要C或者OC风格的贯穿行为,你可以选择switch每个case末尾使用fallthrough关键字

image.png

语句标签

  • 可以用语句标签来给循环语句或者条件语句做标记。在一个条件语句中,你可以使用一个语句标签配合break语句来结束被标记的语句。在循环语句中,你可以使用语句标签来配合break或者continue语句来结束或者继续执行被标记的语句。

image.png

guard

  • gurad语句,类似于if语句,基于布尔值表达式来执行语句。使用guard语句要求一个条件必须是真才能执行guard之后的语句。与if语句不同,guard语句总是有一个else分句--else分句里的代码会在条件不为真的时候执行。

image.png

  • guard
  • 当编写条件语句的时候,左边的代码间距应该是一个"黄金"或者"快乐"的大道。这是说,不要嵌套if语句。多个return语句是OK的。这样可以避免圈复杂度(Cyclomatic Complexity),并且让代码更加容易阅读。因为你的方法的重要部分没有嵌套在分支上,可以很清楚的找到相关的代码。

image.png

image.png

image.png

=>使用guard改进

image.png

检查API的可用性

  • Swift拥有内置的对API可用性的检查功能,它能够确保你不会悲剧地使用了对部属目标不可用的API。
  • 你可以在if或者gurad语句中使用一个可用性条件来有条件地执行代码,基于在运行时你想用的哪个API是可用的。

image.png

func checkIPAddress(ipAddr: String) ->(Int,String) {
   let compoments = ipAddr.split(sepatator:".");
   if compoments.count == 4 {
      if let first = Int(compoments[0]),first >=0 && first < 256 {
        if let second = Int(compoments[1]),second >= 0 && second <256 {
       if let third = Int(compoments[2]), third >= 0 && third < 256 {
       if let fourth = Int(compoments[3]), fourth >= 0 && fourth < 256 {
       return (0,"")
       }else {
         return (4,"the fourth compoments is wrong")
       }
       }else {
         return (3,"the third compoments is wrong")
       }
      }else {
        return (2,"the second compoments is wrong")
        }
      } else {
      return (1,"the first compoments is wrong")
      }
   } else {
      return (100,"the ip address must has four compoments")
   }
}
print(checkIPAddress(ipAddr:"123.0.0.1"))

func checkIPAddress2(ipAddr: String) -> (Int,String) {
 let compoments = ipAddr.split(sepatator:".")
 guard compoments.count == 4 else {
  return (100,"the ip address must has four compoments")
 }
  guard let first = Int(compoments[0]),first >=0 && first < 256 else {
  return (1,"the first compoments is wrong")
 }
  guard let second = Int(compoments[1]),second >= 0 && second <256 else {
  return (2,"the second compoments is wrong")
 }
 guard let third = Int(compoments[2]), third >= 0 && third < 256else {
  return (3,"the third compoments is wrong")
 }
 guard let fourth = Int(compoments[3]), fourth >= 0 && fourth < 256 else {
  return (4,"the fourth compoments is wrong")
 }
 return (0,"")
}
print(checkIPAddress2(ipAddr:"123.0.0.1"))

模式和模式匹配

模式

  • 模式代表单个值或者复合值的结构
  • 例如,元组(1,2)的结构是由逗号分隔的,包含两个元素的列表。因为模式代表一种值的结构,而不是特定的某个值,你可以利用模式来匹配各种各样的值。比如,(x,y)可以匹配元组(1,2),以及任何含两个元素的元组。除了利用模式匹配一个值以外,你可以从复合值中提取出部分或全部值,然后分别把各个部分值和一个常量或变量绑定起来。

模式分类

  • Swift中的模式分为两类:一种能成功匹配任何类型的值,另一种在运行时匹配某个特定值时可能会失败。
  • 第一类模式用于结构简单变量、常量和可选绑定中的值。此类模式包括通配符模式、标识符模式,以及包含前两种模式的值绑定模式和元组模式。你可以为这类模式指定一个类型标注,从而限制它们只能匹配某种特定类型的值。
  • 第二类模式用于全模式匹配,这种情况喜爱你试图匹配的值在运行时可能不存在。此类模式包括枚举用例模式、可选模式、表达式模式和类型转换模式。在switch语句的case标签中,do语句的catch子句中,或者在if、while、guard和for-in语句的case条件句中使用这类模式。
  • 通配符模式(Wildcard Pattern)
  • 标识符模式(Identifier Pattern)
  • 值绑定模式(Value-Binding Pattern)
  • 元组模式(Tuple Pattern)
  • 枚举用例模式(Enumeration Case Pattern)
  • 可选项模式(Optional Pattern)
  • 类型转换模式(Type-Casting Pattern)
  • 表达式模式(Expression Pattern)
通配符模式(Wildcard Pattern)
  • 通配符模式由一个下划线(_)构成,用于匹配并忽略任何值。当你想忽略被匹配的值时可以使用该模式。
for _ in 1...3 {
  // ...
}
标识符模式(Identifier Pattern)
  • 标识符模式匹配任何值,并将匹配的值和一个变量或常量绑定起来
let someValue = 42
值绑定模式(Value-Binding Pattern)

值绑定模式把匹配到的值绑定给一个变量或常量。把匹配带的值绑定给常量时,用关键字let,绑定给变量时,用关键字var.

let point = (3,2)
switch point {
// 将point中的元素绑定到x 和 y
  case let (x,y):
  print("The point is at (\(x),\(y)).")
}
元组模式(Tuple Pattern)
  • 元组模式是由逗号分隔的,具有零个或多个模式的列表,并由一对圆括号括起来。元组模式匹配相应元组类型的值。
  • 可以使用类型标注去限制一个元组模式能匹配哪种元组类型。例如:在常量声明 let (x,y):(Int,Int)=(1,2)中的元组模式(x,y):(Int,Int)只匹配两个元素都是Int类型的元组。
  • 当元组模式被用于for-in语句或者变量和常量声明时,它仅可以包含通配符模式、标识符模式、可选模式或者其他包含这些模式的元组模式。

image.png

枚举用例模式(Enumeration Case Pattern)
  • 枚举用例模式匹配现有的某个枚举类型的某个用例。枚举用例模式出现在swotch语句中的case标签中,以及if、while、guard和for-in语句的case条件中。
可选项模式(Optional Pattern)
  • 可选项模式匹配Optional枚举在some(Wrapped)中包装的值。
  • 可选项目模式为for-in语句提供了一种迭代数组的简便方式,只为数组中非nil得元素执行循环体。

image.png

类型转换模式(Type-Casting Pattern)
  • 有两种类型转换模式,is模式和as模式。is模式只出现在switch语句中的case标签中。is模式和as模式形式如下:
  • is类型
  • 模式as类型
  • is模式仅当一个值的类型在运行时和is模式右边的执行类型一致,或者是其子类的情况喜下,才会匹配这个值。is模式和is运算符有相似表现,它们都进行类型转换,但是is模式没有返回类型。
  • as模式仅当一个值的类型在运行时和as模式右边的指定类型一致,或者其子类的情况下,才会匹配这个值。如果匹配成功,被匹配的值的类型被转换成as模式右边指定的类型。

image.png

image.png

表达式模式(Expression Pattern)
  • 表达式模式代表表达式的值。表达式模式只出现在switch语句中的case标签中
  • 表达式模式代表的表达式会使用Swift标准库中的~=运算符与输入表达式的值进行比较。如果~=运算符返回true,则匹配成功。默认情况下,~=运算符使用==运算符来比较两个相同类型的值。它也可以将一个整型数值与一个Range实例中的一段整数区间做匹配。

image.png

  • 自定义类型默认也是无法进行表达式模式匹配的,也需要重载 ~= 运算符

image.png