函数


  • 定义:一段完成特定任务的独立代码片段。
  // 1. 没有参数没有返回值的函数
  func about() -> Void {
    print("iPhone 7s")
  }
  abount()

  // 2. 有参数没有返回值的函数
  func callPhone(phoneNumber: String) {
    print("打电话给:\(phoneNumber)")
  }
  callPhone(phoneNumber: "+86 110")  

  // 3. 没有参数有返回值的函数
  func readMessage() -> String {
    return "吃饭了吗?"
  }  
  let msg = readMessage()
  print(msg)

  // 4. 有参数有返回值的函数
  func sum(num1: Int, num2: Int) -> Int {
    return num1 + num2
  }
  let result = sum(num1: 20, num2: 30)
  print(result)

  // 5. 有参数有多个返回值的函数
  let nums = [10, 11, 15, 20, 111]
  func getOddEvenCount(nums: [Int]) -> (Int, Int) {
    var oddCount = 0
    var evenCount = 0
    for n in nums {
      if n % 2 = 0 {
        evenCount += 1
      } else {
        oddCount += 1
      }
    }
    return (oddCount, evenCount)
  }
  let tuple = getOddEvenCount(nums: nums)
  print("奇数:\(tuple.0) 偶数:\(tuple.1)")
  • 参数
  * 基础用法
    1. 每个函数参数都有一个参数标签(argument label) 和 一个参数名称(parameter name);
     2. 参数标签在调用函数的时候使用,调用的时候需要将函数的参数标签写在对应的参数名称前面;  
      3. 参数名称在函数的实现中使用;
       4. 默认情况下,函数参数使用参数名称来作为它们的参数标签。

    实例代码:
    func greet(person: String, from hometown: String) -> String {
      return "Hello \(person)! Glad you could visit from \(hometown)"
    }   
    print(greet(person: "Bill", from: "Cupertino"))

  ** 忽略参数标签:使用一个下划线(_)来代替一个明确的参数标签
     func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
       print(firstParameterName, secondParameterName)
     }
     someFunction(1, secondParameterName: 2)

  *** 默认参数:在函数体中通过给参数赋值来为任意一个参数定义默认值
      func makeCoffee(coffeeName: String = "雀巢") -> String {
        return "制作了一杯爱心的\(coffeeName)咖啡。"
      }
      makeCoffee()
      makeCoffee(coffeeName: "拿铁")
      makeCoffee(coffeeName: "卡布奇诺")

  **** 可变参数:一个函数最多只能拥有一个可变参数
       func sum(nums: Int...) Int {
         var total = 0
         for n in nums {
           total += n
         }
         return total
       } 
       sum(nums: 20, 30, 40)  

  ***** 输入输出参数
        1. 函数参数默认是常量;
         2. 想要一个函数可以修改参数的值,并且想要这些修改在函数调用结束后仍然存在;
          3. 应该把这个参数定义为输入输出参数,并且只能传递变量给输入输出参数;
           4. 用 inout 修饰的参数,不能设定默认值。

        示例代码:
        func swapTwoInts(_ a: inout Int, _ b: inout Int) {
          let temporaryA = a
          a = b
          b = temporaryA
        } 
        var anotherInt = 107
        swap(&someInt, &anotherInt)               
        print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
  • 类型
  1. 定义:由函数的参数类型和返回类型组成。
     示例代码:
     // 这个函数的类型是:(Int, Int) -> Int
     func addTwoInts(_ a: Int, _ b: Int) -> Int {
        return a + b
     }

  2. 作为数据类型
     func addTwoInts(_ a: Int, _ b: Int) -> Int {
        return a + b
     }
     func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
        return a * b
     }
     var mathFunction: (Int, Int) -> Int = addTwoInts
     print("Result: \(mathFunction(2, 3))")
     mathFunction = multiplyTwoInts
     print("Result: \(mathFunction(2, 3))")
     let anotherMathFunction = addTwoInts

  3. 作为返回类型
     func stepForward(_ input: Int) -> Int {
        return input + 1
     }
     func stepBackward(_ input: Int) -> Int {
        return input - 1
     }
     func chooseStepFunction(backward: Bool) -> (Int) -> Int {
        return backward ? stepBackward : stepForward
     }
     var currentValue = 3
     let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
     print("Counting to zero")
     while currentValue != 0 {
        print("\(currentValue)")
        currentValue = moveNearerToZero(currentValue)
     }
     print("zero!")

闭包


  • 定义:一种利用简介语法构建内联闭包的方式。
  三种形式:
  1. 全局函数:一个有名字但不会捕获任何值的闭包;
  2. 嵌套函数:一个有名字并可以捕获其封闭函数域内值的闭包;
  3. 闭包表达式:一个利用轻量级语法所写的可以捕获和存储其上下文中常量或者变量的匿名闭包。

  func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
  }
  let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
  let reversedNames = names.sorted(by: backward)
  print("reversedNames")

  // 闭包表达式写法:
  1. 类型:(形参列表) -> 返回值;
   2. 值:{ (形参列表) -> 返回值 in 代码块 };
    3. 调用:常量或变量名称(形参列表); 
     4. 不能在闭包参数中设置默认值。
  let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
  var reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
     return s1 > s2 
  })
  print("1: \(reversedNames)")
  // 根据上下文推断类型:省略围绕在参数周围的括号 和 返回箭头 ->
  reversedNames = names.sorted(by: { s1, s2 in return s1 > s2})
  print("2: \(reversedNames)")
  // 单行表达式闭包隐式返回:省略 return
  reversedNames = names.sorted(by: { s1, s2 in s1 > s2 })
  print("3: \(reversedNames)")
  // 参数名称缩写:省略参数名称 和 in
  reversedNames = names.sorted(by: { $0 > $1 })
  print("4: \(reversedNames)")
  // 运算符方法
  reversedNames = names.sorted(by: >)
  print("5: \(reversedNames)")
  • 值捕获
  1. 闭包在其被定义的上下文中捕获常量或者变量;
  2. 即使定义这些常量和变量的原作用域已经不存在;
  3. 闭包仍然可以在闭包函数体内引用和修改这些值。

  func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
      runningTotal += amount
      return runningTotal
    }
    return incrementer
  }
  let incrementByTen = makeIncrementor(forIncrement: 10)
  incrementByTen()
  // 如果创建另一个 incrementor,它会有属于自己的引用,指向一个全新、独立的 runningToral 变量
  let incrementBySeven = makeIncrementor(forIncrement: 7)
  incrementBySeven()
  • 闭包是引用类型
  1. 将函数或者闭包赋值给一个常量还是变量;
   2. 实际上都是将常量或者变量的值设置为对应函数或者闭包的引用。
  • 尾随闭包
  1. 需要将一个很长的闭包表达式作为最后一个参数传递给函数;
   2. 在使用尾随闭包时,可以将闭包表达式书写在函数括号之后;
    3. 在使用尾随闭包时,不用写出它的参数标签。

  示例代码:  
  func calculate(opr: String, funN: (Int, Int) -> Int) {
    switch opr {
      case "+":
        print("10 + 5 = \(funN(10, 5))")
      default:
        print("10 - 5 = \(funN(10, 5))")  
    }
  }
  calculate(opr: "+", funN: { (a: Int, b: Int) -> Int in return a + b })
  calculate(opr: "-") { (a: Int, b: Int) -> Int in return a + b }

   如果闭包表达式是函数或者方法的唯一参数,则使用尾随闭包时,可以把 () 省略掉
     let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
     let reversedNames = names.sorted { $0 > $1 }

     // 改变数组元素所映射的值
     let digitNames = [
                       0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four", 
                       5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
                      ]
     let numbers = [16, 58, 510]
     let strings = numbers.map { (number) -> String in 
       var number = number
       var output = ""
       repeat {
         output = digitNames[number % 10]! + output
         number /= 10
       } while number > 0
       return output
     }
     print(strings)
  • 逃逸闭包
  1. 一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行;
   2. 在参数类型之前标注 @escaping;
    3. 在逃逸闭包中,必须显示地引用 self// 将闭包保存在一个函数外部定义的变量中
  var completionHandlers: [() -> Void] = []
  func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
  }
  func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
  } 
  class SomeClass {
    var x = 10
    func doSomething() {
      someFunctionWithEscapingClosure {
        // 必须显示地引用 self
        self.x = 100
      }
      someFunctionWithNonescapinClosure {
        x = 200
      }
    }
  }
  let instance = SomeClass()
  instance.doSomething()
  print(instance.x)
  completionHandlers.first?()
  print(instance.x)
  • 自动闭包
  1. 一种自动创建的闭包,用于包装传递给函数作为参数的表达式;
   2. 不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值;
    3. 在参数类型之前标注 @autoclosure4. 一般用来延迟求值。

  示例代码:
  var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
  print(customersInLine.count)
  let customerProvider = {customersInLine.remove(at: 0)}
  print(customersInLine.count)
  print("Now serving \(customerProvider())!")
  print(customersInLine.count)   
  // 闭包作为参数传递给函数
  func serve(customer customerProvider: () -> String) {
    print("Now serving \(customerProvider())!")
  }
  serve(customer: { customersInLine.remove(at: 0) } )
  // 将参数标记为 @autoclosure 来接收一个自动闭包
  func serve(customer customerProvider: @autoclosure () -> String) {
    print("Now serving \(customerProvider())!")
  }
  serve(customer: customersInLine.remove(at: 0))

results matching ""

    No results matching ""