Swift5.0 - day2-流程控制、函数、枚举

作者: IIronMan | 来源:发表于2019-06-21 17:36 被阅读25次

    一、流程控制

    • 1.1、if 语句

      let age = 5
      if age > 10  {
          print("\(age) 大于 10 ")
      } else if  age > 3 {
          print("\(age) 大于 3 ")
      } else {
          print("\(age) 小于 3 ")
      }
      

      提示:

      • if 后面的条件可以省略小括号,而条件后面的大括号不可以省略
      • if 后面的类型只能是 bool 类型


        if 后面的类型只能是 bool 类型
    • 1.2、while 语句(先判断后执行)

      var num = 5
      while num > 0 {
           num -= 1
           print("num=\(num)")
      }
      

      打印结果:num=4、num=3、num=2、num=1、num=0

    • 1.3、repeat while 语句(先执行后判断)

      var num = -1
      repeat{
          print("num=\(num)")
      }while num > 0
      

      打印结果:num=-1,

      提示:repeat-while 相当于 OC 里面的 do-while

    • 1.4、for 语句

      • 闭区间运算符:a...ba<= 取值 <=b

        let names = ["小1","小2","小3","小4"]
        for i in 0...3 {
             print("name=\(names[i])")
        }
        

        提示:上面的 0...3 可以替换为 let range = 0...3

        let a =  0
        var b = 3
        
        let names = ["小1","小2","小3","小4"]
        for i in a...b {
            print("name=\(names[i])")
        }
        

        提示:区间可以用常量或者变量来表示的

        for _ in 0...3 {
            print("😆")
        }
        

        打印了 四次 😆

      • for 循环里面的 i 默认是 let,有需要的时候我们可以声明为 var,如下

        for var i in 1...3 {
            i += 2
            print("i=\(i)")
        }
        

        打印结果:3、4、5

      • 半开区间运算符:a..<ba <= 取值 < b

        for i in 1..<3 {
        
           print("i=\(i)")
        }
        

        打印结果:1、2

    • 1.5、for - 区间运算符用在数组上

      • 例一

        let names = ["小1","小2","小3","小4"]
        for name in names[0...3] {
             print("name=\(name)")
        }
        

        打印结果:小1、小2、小3、小4

      • 例二:单侧区间:让区间朝一个方向尽可能的远

        let names = ["小1","小2","小3","小4"]
        for name in names[1...] {
            print("name=\(name)")
        }
        

        打印结果:小2、小3、小4

        let names = ["小1","小2","小3","小4"]
        for name in names[...2] {
            print("name=\(name)")
        }
        

        打印结果:小1、小2、小3

        let names = ["小1","小2","小3","小4"]
        for name in names[..<2] {
            print("name=\(name)")
        }
        

        打印结果:小1、小2

        let range = ...5
        print(range.contains(8))
        print(range.contains(3))
        print(range.contains(-1))
        

        打印结果:false、true、true

        提示: let range = ...5 代表 range的范围从无穷小到 5,包含5

    • 1.6、区间类型(重点)

      let range1:ClosedRange<Int> = 1...3
      let range2:Range<Int> = 1..<3
      let range3:PartialRangeThrough<Int> = ...5
      
      • 字符、字符串也能进行区间运算,但默认不能在 for-in

        let stringRange1 = "cc"..."ff" // ClosedRange<String>
        stringRange1.contains("cb")   // false
        stringRange1.contains("dz")   // true 
        stringRange1.contains("fg")   // false
        
        let stringRange2 = "a"..."f"  // ClosedRange<String>
        stringRange2.contains("d")    // true
        stringRange2.contains("n")    // false
        
      • 0到~包含了所有可能要用到的 ASCII 字符

        let characterRange:ClosedRange<Character> = "\0"..."~"
        characterRange.contains("b")   // true
        
    • 1.8、带间隔的区间值

      let hours = 12
      let hourInterval = 2
      // 从tickMark 的取值:从 4 开始,累加2,不超过 11
      for tickMark in stride(from: 4, to: hours, by: hourInterval) {
          print("tickMark=\(tickMark)")
      }
      

      打印结果:4、6、8、10

    • 1.9、switch 语句

      • 案例一:switch的基本使用

        var num = 10
        switch num {
        case 1:
             print("值是1")
             break
        case 2:
             print("值是2")
             break
        case 3:
             print("值是3")
             break
        default:
             print("没有匹配")
             break
        }
        

        提示:case 和 default 后面不能写大括号 {},默认可以不写 break,并不会贯穿到后面的条件

      • 案例二:使用 fallthrough 可以实现贯穿效果

        var num = 1
        switch num {
        case 1:
           print("num 值是 1")
           fallthrough
        case 2:
           print("num 值是 2")
        case 3:
           print("num 值是 3")
        default:
           print("没有匹配")
        }
        

        打印结果:num 值是 1、num 值是 2

      • switch使用注意点:

        • <1>、switch 必须能保证处理所有的情况


          switch 必须能保证处理所有的情况
        • <2>、case 或者 default 后面至少有一条语句,如果不想有语句可以写 break

          var num = 1
          switch num {
          case 1:
              print("num 值是 1")
          case 2:
              break
          default:
              print("没有匹配")
          }
          
        • <3>、如果能保证处理所有的情况,也可以不必使用 default,如下

          enum Answer {case right,wrong}
          let answer = Answer.right
          switch answer {
          case Answer.right:
              print("right")
          case Answer.wrong:
              print("wrong")
          }
          

          提示:上面已经确定 answer 是 Answer 类型,因此可以省略 Answer

          enum Answer {case right,wrong}
          let answer = Answer.right
          switch answer {
          case .right:
               print("right")
          case .wrong:
               print("wrong")
          }
          
      • 复合条件:switch也支持Character、String 类型,如下例子

        • 例一:String 类型

          let name = "marry"
          switch name {
          case "Jack":
              print("Jack")
          case "marry":
              print("marry")
          default:
              print("找不到某人")
          }
          
        • 例二:String 类型

          let name = "marry"
          switch name {
          case "Jack","marry":
              print("Jack and marry")
          default:
              print("找不到某人")
          }
          
        • 例三:Character 类型

          let character = "A"
          switch character {
          case "a","A":
              print("字母 a或者A")
          default:
              print("找不到字母")
          }
          
      • 匹配区间和元组匹配

        • 匹配区间

          let count = 20
          switch count {
          case 0:
             print("none")
          case 1..<5:
             print("a few")
          case 5..<100:
             print("several")
          case 100..<1000:
             print("hundreds of")
          default:
             print("many")
          }
          
        • 元组匹配

          let point = (1,1)
          switch point {
          case (0,0):
             print("the origin")
          case (_,0):
             print("on the x-axis")
          case (0,_):
             print("on the y-axis")
          case (-2...2,-2...2):
             print("inside the box")
          default:
             print("many")
          }
          

          提示:可以使用 _ 忽略某个值

      • 值绑定:必要时,let 可以改为 var

        let point = (2,0)
        switch point {
        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 an y value of \(y)")
        case let (x,y):
           print("somehere else at (\(x),\(y))")
        }
        
    • 1.10、where语句

      let point = (2,-2)
      switch point {
      case let (x,y) where x == y:
          print("on the line x == y")
      case let (x,y) where x == -y:
          print("on the line x == -y")
      case let (x,y):
          print("(\(x),\(y)) is just some arbitrary point")
      }
      

      例二:所有的正数相加

      let numbers = [-1,2,3,-10,20]
      var sum = 0
      for num in numbers where num > 0 {
      
         sum += num
      }
      print("最后正数的和=\(sum)")
      

      提示:where 用来过滤 负数

    • 1.11、标签语句

      outer: for i in 1...4{
      
         for k in 1...4 {
        
            if k == 3 {
                continue outer
            }
            if i == 3 {
                break outer
            }
            print("i=\(i) k=\(k)")
         }
      }
      

    二、函数

    • 2.1、函数的定义

      • 有返回值,有参数

        func pi()->Double{
            return 3.14
        }
        print(pi())
        
        func sum(num1:Int,num2:Int)->Int{
            return num1 + num2
        }
        print(sum(num1: 1, num2: 3))
        

        提示:形参默认是 let,也只能是 let

      • 无返回值,无参数;下面的几种 无返回值表达的意思是一样的

        func sayHello()->Void{
           print("Hello")
        }
        
        func sayHello()->(){
           print("Hello")
        }
        
        func sayHello(){
           print("Hello")
        }
        
    • 2.2、函数的隐式返回 (有疑问)?????

      func sum(num1:Int,num2:Int) -> Int{
           num1 + num2
      }
      sum(num1: 1, num2: 3)
      

      提示:如果整个函数的整体是一个单一的表达式,那么函数会隐式返回这个表达式

    • 2.3、返回元组 和 实现多值返回

      func calculate(v1: Int,v2:Int) -> (sum:Int,difference:Int,average:Int){
      
           let sum = v1 + v2
           return (sum,v1-v2,sum>>1)
      }
      
      let result = calculate(v1: 20, v2: 10)
      result.sum   // 和 
      result.difference  // 差 : 10
      result.average   // 二进制右移 是 平均值 15
      

      提示:sum>>1 代表值的二进制数 右移 求平均值

    • 2.4、函数的文档注释 参考苹果的链接

      /// 求和 【概述】
      ///
      /// 将两个整数相加 【更详细的描述】
      ///
      /// - Parameter v1: 第 1 个整数
      /// - Parameter v2: 第 2 个整数
      /// - Returns : 两个整数的和
      ///
      /// - Note:传入两个整数即可 【批注】
      ///
      func sum(_ v1:Int,_ v2:Int) -> Int{
          return v1 + v2
      }
      
      sum(10, 20)
      

      效果如下:


    • 2.5、参数标签

      • 可以修改参数标签

        func goToWork(at time:String){
        
             print("this time is \(time)")
        }
        
        goToWork(at: "08:00")
        

        打印结果:this time is 08:00

      • 可以使用下划线 _ 省略参数标签

        func sum(_ v1:Int,_ v2:Int) -> Int{
            return v1 + v2
        }
        
        sum(10, 20)
        
    • 2.6、默认参数值(Default Parameter Value)

      • 参数可以有默认值

        func check(name:String = "noPerson",age:Int,job:String = "iOS"){
        
            print("名字=\(name) 年龄=\(age) 工作=\(job)")
        }
        
        check(name: "老大", age: 19, job: "iOS")
        check(name: "老二", age: 19)
        check(age: 10, job: "前端")
        check(age: 16)
        

        提示:只要是有默认参数值的就可以不传参数

        • C++的默认参数值有个限制:必须从右往左设置。由于Swift拥有参数标签,因此并没有此类限制

        • 但是在省略参数标签时,需要特别注意,避免出错,如下
          这里的 two 不可以省略参数标签

          func test(_ one:Int = 10,two:Int,_ three:Int = 20){
          
              print("打印 one = \(one) two = \(two) three = \(three)")
          }
          
          test(two: 9)
          
    • 2.7、可变参数(Variadic Parameter)

      func sum(_ numbers: Int...)->Int{
      
         var total = 0
         for i in numbers {
             total += I
         }
         return total
      }
      
      sum(1,2,3)
      

      提示:一个函数 最多只能有1个 可变参数;紧跟在可变参数后面的参数不能省略参数标签,如下

      func test(_ numbers:Int...,string:String,_ other:String){
      
      }
      
      test(1,2,3, string: "iOS", "Rose")
      

      参数 string 标签不能省略

    • 2.8、Swift 自带的 print 函数

      /// - Parameters:
      ///   - items: Zero or more items to print.
      ///   - separator: A string to print between each item. The default is a single
      ///     space (`" "`).
      ///   - terminator: The string to print after all items have been printed. The
      ///     default is a newline (`"\n"`).
      public func print(_ items: Any..., separator: String = " ", terminator: String = "\n")
      

      分析: 第一个参数是要打印的值,第二个参数是:连接第一个参数值的 字符,第三个参数是:默认是 \n 换行,如下例子

      print(1,2,3,4,5)
      print(1,2,3, separator: "_")
      print(1,2,3, separator: "_", terminator: "")
      print("哈哈")
      

      打印结果是: 最后一行不换行,因为 "\n" 被用 "" 取代了

      1 2 3 4 5
      1_2_3
      1_2_3哈哈
      
    • 2.9、输入输出参数 (In-Out Parameter)
      可以用 inout 定义一个输入输出函数:可以在函数内部修改外部实参的值

      func swapValues(_ v1:inout Int,_ v2:inout Int){
      
          let tem = v1
          v1 = v2
          v2 = tem
      }
      
      var num1 = 10
      var num2 = 20
      swapValues(&num1, &num2)
      
      print(num1,num2)
      

      打印结果:20 10

      • 提示:下面的函数与上面的等价:传进去的是 内存地址,所以可以修改其外部参数的值

        func swapValues(_ v1:inout Int,_ v2:inout Int){
        
           (v1,v2) = (v2,v1)
        }
        
      • 可变参数不能标记为 inout

      • 输入输出参数不能有默认值

      • 输入输出参数不能传入常量(let)、字面量作为实参

    • 2.10、函数重载 (Function Overload)
      规则:函数名相同
      参数个数不同 || 参数类型不同 || 参数标签不同

      func sum(v1:Int,v2:Int) -> Int{
         return v1 + v2
      }
      

      参数个数不同

      func sum(v1:Int,v2:Int,v3:Int) -> Int{
          return v1 + v2
      }
      

      参数类型不同

      func sum(v1:Int,v2:Double) -> Double{
         return Double(v1) + v2
      }
      
      func sum(v1:Double,v2:Int) -> Double{
         return v1 + Double(v2)
      }
      

      参数标签不同

      func sum(_ v1:Int,_ v2:Int) -> Int{
         return v1 + v2
      }
      
      func sum(a:Int,b:Int) -> Int{
         return a + b
      }
      
      • 函数重载注意点一: 返回值类型 与 函数重载 无关

        func sum(a:Int,b:Int) -> Int{
            return a + b
        }
        
        func sum(a:Int,b:Int) {
        
        }
        
        sum(a: 1, b: 2)
        
      • 函数重载注意点二:默认参数值和函数重载一起使用产生二义性时,编译器并不会报错(在 C++ 中会报错)

        func sum(a:Int,b:Int) -> Int{
             return a + b
        }
        
        func sum(a:Int,b:Int,c:Int) {
            return a + b + c
        }
        // 会调用 sum(a:Int,b:Int)
        sum(a: 1, b: 2)
        
      • 函数重载注意点三:可变参数,省略参数标签,函数重载一起使用产生二义性时,编译器有可能会报错

        func sum(a:Int,b:Int) -> Int{
            return a + b
        }
        
        func sum(_ a:Int,_ b:Int) -> Int {
            return a + b
        }
        
        func sum(_ numbers: Int...)->Int{
        
            var total = 0
            for i in numbers {
                total += I
            }
            return total
        }
        

        调用 sum(1,2) 报错:Ambiguous use of 'sum'

    • 2.11、内联函数(Inline function)

      • 如果开启了编译器优化(Release模式默认会开启优化),编译器会默认将某些函数变成内联函数
        • 将函数调用展开成函数体
        将函数调用展开成函数体
        不会被内联的函数:函数体比较长、包含递归调用、包含动态派发......
    • 2.12、函数类型:每一个函数都是有类型的,函数的类型由:形式参数类型,返回值类型组成

      • 例子一:无参数无返回值

        func test() {}
        
      • 例子二:有参数有返回值

        func test(a:Int,b:Int) -> Int {
           return a + b
        }
        
      • 例子三:调用的时候不需要传参数标签

        func test(Int,Int) -> Int {
           return a + b
        }
        test(2,3)  // 调用的时候不需要传参数标签
        
    • 2.13、函数类型作为函数参数

      func sum(a:Int,b:Int) -> Int{
          return a + b
      }
      func difference(a:Int,b:Int) -> Int{
          return a - b
      }
      func printResult(_ mathFn:(Int,Int)->Int,_ a:Int,_ b:Int){
          print("result=\(mathFn(a,b))")
      }
      
      printResult(sum, 5, 2)  // 打印结果:result=7
      printResult(difference, 5, 2) // 打印结果:result=3
      
    • 2.14、函数类型作为函数返回值

      func next(_ input:Int)->Int{
      
          return input + 1
      }
      
      func previous(_ input:Int)->Int{
      
          return input - 1
      }
      
      func forward(_ forward:Bool)->(Int)->Int{
      
          return forward ? next:previous
      }
      
      print(forward(true)(3))  //  结果:4
      print(forward(false)(3))  //  结果:2
      

      提示:返回值是函数的函数,叫做高阶函数(Height-Order Function)

    • 2.15、typealias: 用来给类型起别名

      typealias Byte = Int8
      typealias Short = Int16
      typealias Long = Int64
      

      如下:

      typealias Date = (year:Int,month:Int,day:Int)
      
      func test(_ date:Date){
      
          print(date.year,date.month,date.day)
      }
      
      test((2019,6,19))
      

      例二:(重点👂👂👂👂👂👂👂👂👂👂)

      typealias IntFn = (Int,Int) -> Int
      
      func difference(v1:Int,v2:Int)->Int{
           return v1-v2
      }
      let fn:IntFn = difference
      
      fn(20,10)
      
      func setFn(_ fn:IntFn){}
      setFn(difference)
      
      func getFn() -> IntFn{
      
          return difference
      }
      
    • 2.16、嵌套函数: 将函数定义在函数的内部

      func forward(_ forward:Bool)->(Int)->Int{
      
          func next(_ input:Int)->Int{
        
               return input + 1
          }
      
          func previous(_ input:Int)->Int{
        
               return input - 1
          }
      
          return forward ? next:previous
      }
      
      forward(true)(3)  // 4
      forward(false)(3) // 2
      

    三、枚举

    • 3.1、枚举的基本用法

      enum Direction {
          case north
          case south
          case east
          case west
      }
      
      enum Direction {
          case north,south,east,west
      }
      

      使用如下:

      var dircetion = Direction.north
      dircetion = Direction.west
      dircetion = .south
        
      print("dircetion=\(dircetion)")
      
      let dir = Direction.north
        
      switch dir {
      case .north:
            print("north")
      case .south:
            print("south")
      case .east:
            print("east")
      case .west:
            print("west")
      }
      
    • 3.2、关联值(Associated Values)

      • 有时会将枚举的成员值跟其他类型的关联存储在一起,会非常有用

        enum Score {
            case points(Int)
            case grade(Character) 
        }
        
        var source = Score.points(96)
        source = .grade("A")
        
        switch source {
        case let .points(i):
           print(i,"points")
        case let .grade(i):
          print("grade",i)
        }
        

        打印结果:grade A

      • 下面代码必要的时候 let 可以改为 var

         enum Date{
        
             case digit(year:Int,month:Int,day:Int)
             case string(String)
         }
        
         var date = Date.digit(year:2019,month:6,day:21)
         date = .string("2019-6-21")
        
         switch date {
         case .digit(let year,let month,let day):
              print(year,month,day)
         case let .string(value):
              print(value)
         }
        

        打印结果:2019-6-21

      • 关联值举例


        关联值手势举例
        enum Password{
        
           case number(Int,Int,Int,Int)
           case gesture(String)
        }
        
        var pwd = Password.number(3,5,7,8)
        pwd = .gesture("12368")
        
        switch pwd {
        case let .number(n1,n2,n3,n4):
            print("number is \(n1) \(n2) \(n3) \(n4)")
        case let .gesture(str):
            print("gesture is",str)
        }
        

        打印结果:gesture is 12368

    • 3.3、原始值 (Raw Values):枚举成员可以使用相同类型的默认值预先关联,这个默认值叫做:原始值

      enum PlayingCards : Character{
      
          case A = "a"
          case B = "b"
          case C = "c"
          case D = "d"
      }
      
      var suit = PlayingCards.A
      
      print(suit)   // A
      print(suit.rawValue) // a
      print(PlayingCards.D.rawValue) // d
      
      enum Grade : String{
      
         case perfect = "A"
         case great = "B"
         case good = "C"
         case bad = "D"
      }
      
      print(Grade.perfect.rawValue)   // A
      print(Grade.great.rawValue)     // B
      print(Grade.good.rawValue)      // C
      print(Grade.bad.rawValue)       // D
      
    • 3.4、隐式原始值 (Implicitly Assignd RawValues):如果枚举的原始类型是Int、String 类型,Swift会自动分配原始值

      • String 类型

        enum Direction {
             case north,south,east,west
        }
        print(Direction. north) // north
        print(Direction. north.rawValue) // north
        

        等价于

        enum Direction {
           case north =  "north"
           case south =  "south"
           case east =  "east"
           case west =  "west"
        }
        
      • Int 类型

        enum Season:Int{
        
           case spring,summer,autumn,winter
        }
        
        print(Season.spring.rawValue)   // 0
        print(Season.summer.rawValue)  // 1
        print(Season.autumn.rawValue)  // 2
        print(Season.winter.rawValue)  // 3
        
      • Int 类型设置了默认原始值,设置了值之后 Swift会自动递增原始值

        enum Season:Int{
        
           case spring = 2,summer,autumn = 5,winter
        }
        
        print(Season.spring.rawValue)   // 2
        print(Season.summer.rawValue)  // 3
        print(Season.autumn.rawValue)  // 5
        print(Season.winter.rawValue)  // 6
        
    • 3.5、递归枚举 (Recursive Enumeration)

      enmu ArithExpr{
          case number(Int)
          indirect case sum(ArithExpr,ArithExpr)
          indirect case difference(ArithExpr,ArithExpr)
      }
      
      let five = ArithExpr.number(5)
      let four = ArithExpr.number(4)
      let two = ArithExpr.number(2)
      let sum = ArithExpr.sum(five,four)
      let difference = ArithExpr.difference(sum,two)
      
      func calculate(_ expr:ArithExpr) -> Int{
      
          switch expr {
          case let .number(value):
             return value
          case let .sum(left,right):
             return calculate(left) + calculate(right)
          case let .difference(left,right):
             return calculate(left) - calculate(right)
          }
      }
      
      calculate(difference)
      
    • 3.7、MemoryLayout: 获取数据类型占用的内存大小

      enum Password{
      
          case number(Int,Int,Int,Int)  // 32 字节
          case other  // 1 个字节就搞定了
      }
      
      MemoryLayout<Password>.stride   // 40 分配占用的内存空间大小
      MemoryLayout<Password>.size  // 33 实际用到的空间大小
      MemoryLayout<Password>.alignment  // 8 对齐参数
      
      var password = Password.number(2,3,4,5)
      password = .other
      
      MemoryLayout.stride(ofValue:password)   // 40
      MemoryLayout.size(ofValue:password)  // 33
      MemoryLayout.alignment(ofValue:password)  // 8
      

      提示:stride:范围 与 size 的区别
      size: 分配占用的内存空间大小
      stride: 实际用到的空间大小
      内存对齐是 8个字节 ,所以上面是 32+1 = 40

    • 3.8、拓展:枚举的关联值(3.2) 和 默认原始值(3.3) 的区别
      分析:枚举的关联值 的值 是写到枚举的内存中的,而枚举的原始值是固定死的,没有写入枚举的内存中
      举例如下:

      enum Season:Int{
      
          case spring,summer,autumn,winter
      }
      
      MemoryLayout<Season>.stride   // 1
      MemoryLayout<Season>.size  // 1
      MemoryLayout<Season>.alignment  // 1
      

    相关文章

      网友评论

        本文标题:Swift5.0 - day2-流程控制、函数、枚举

        本文链接:https://www.haomeiwen.com/subject/kwexqctx.html