Swift - 闭包

  • 简述

    Swift 4 中的闭包类似于以块形式组织并在任何地方调用的自包含函数,如 C 和 Objective C 语言。函数内部定义的常量和变量引用被捕获并存储在闭包中。函数被认为是闭包的特殊情况,它采用以下三种形式 -
    全局函数 嵌套函数 闭包表达式
    有一个名字。不捕获任何值 有一个名字。从封闭函数中捕获值 未命名闭包从相邻块中捕获值
    Swift 4 语言中的闭包表达式遵循清晰、优化和轻量级的语法风格,其中包括。
    • 从上下文推断参数和返回值类型。
    • 单表达式闭包的隐式返回。
    • 简写参数名称和
    • 尾随闭包语法

    句法

    以下是定义接受参数并返回数据类型的闭包的通用语法 -
    
    {
       (parameters) −> return type in
       statements
    }
    
    以下是一个简单的例子 -
    
    let studname = { print("Welcome to Swift Closures") }
    studname()
    
    当我们使用操场运行上述程序时,我们得到以下结果 -
    
    Welcome to Swift Closures
    
    以下闭包接受两个参数并返回一个 Bool 值 -
    
    {     
       (Int, Int) −> Bool in
       Statement1
       Statement 2
       ---
       Statement n
    }
    
    以下是一个简单的例子 -
    
    let divide = {
       (val1: Int, val2: Int) -> Int in 
       return val1 / val2 
    }
    let result = divide(200, 20)
    print (result)
    
    当我们使用操场运行上述程序时,我们得到以下结果 -
    
    10
    
  • 闭包中的表达式

    嵌套函数提供了一种命名和定义代码块的便捷方式。而不是表示整个函数声明和名称构造用于表示较短的函数。通过闭包表达式以清晰的简短语句和重点语法来表示函数。

    升序程序

    对字符串进行排序是通过标准库中已经提供的 Swift 4s 键保留函数“sorted”来实现的。该函数将按升序对给定的字符串进行排序,并返回与旧数组中提到的大小和数据类型相同的新数组中的元素。旧数组保持不变。
    排序函数内表示两个参数 -
    • 已知类型的值表示为数组。
    • 数组内容 (Int, Int) 并返回一个布尔值 (Bool) 如果数组排序正确,它将返回真值,否则将返回假。
    写入带有输入字符串的普通函数并将其传递给 sorted 函数以将字符串排序为新数组,如下所示 -
    
    func ascend(s1: String, s2: String) -> Bool {
       return s1 > s2
    }
    let stringcmp = ascend(s1: "Swift 4", s2: "great")
    print (stringcmp)
    
    当我们使用操场运行上面的程序时,我们得到以下结果 -
    
    true
    
    要为冰淇淋排序的初始数组被指定为“Swift 4”和“great”。对数组进行排序的函数被声明为字符串数据类型,其返回类型被称为布尔值。两个字符串都按升序进行比较和排序,并存储在一个新数组中。如果排序执行成功,该函数将返回真值,否则将返回假。
    闭包表达式语法使用 -
    • 常数参数,
    • 可变参数,以及
    • 输入参数。
    闭包表达式不支持默认值。可变参数和元组也可以用作参数类型和返回类型。
    
    let sum = {
       (no1: Int, no2: Int) -> Int in 
       return no1 + no2 
    }
    let digits = sum(10, 20)
    print(digits)
    
    当我们使用操场运行上述程序时,我们得到以下结果 -
    
    30
    
    函数语句中提到的参数和返回类型声明也可以用带有'in'关键字的内联闭包表达式函数来表示。一旦声明了参数和返回类型,'in' 关键字用于表示闭包的主体。
  • 单表达式隐式返回

    在这里,排序函数的第二个参数的函数类型清楚地表明闭包必须返回一个 Bool 值。因为闭包的主体包含一个返回 Bool 值的单个表达式 (s1 > s2),所以没有歧义,并且可以省略 return 关键字。
    要在表达式闭包中返回单个表达式语句,在其声明部分省略 'return' 关键字。
    
    var count:[Int] = [5, 10, -6, 75, 20]
    let descending = count.sorted(by: { n1, n2 in n1 > n2 })
    let ascending = count.sorted(by: { n1, n2 in n1 < n2 })
    print(descending)
    print(ascending)
    
    当我们使用操场运行上述程序时,我们得到以下结果 -
    
    [75, 20, 10, 5, -6]
    [-6, 5, 10, 20, 75]
    
    该语句本身清楚地定义了当 string1 大于 string2 时返回 true 否则返回 false 因此这里省略 return 语句。
  • 已知类型的闭包

    考虑两个数字的相加。我们知道加法将返回整数数据类型。因此,已知类型的闭包被声明为 -
    
    let sub = {
       (no1: Int, no2: Int) -> Int in 
       return no1 - no2 
    }
    let digits = sub(10, 20)
    print(digits)
    
    当我们使用操场运行上述程序时,我们得到以下结果 -
    
    -10
    
  • 将速记参数名称声明为闭包

    Swift 4 自动为内联闭包提供速记参数名称,可用于通过名称 $0、$1、$2 等引用闭包参数的值。
    
    var shorthand: (String, String) -> String
    shorthand = { $1 }
    print(shorthand("100", "200"))
    
    这里,$0 和 $1 指的是闭包的第一个和第二个 String 参数。
    当我们使用操场运行上述程序时,我们得到以下结果 -
    
    200
    
    Swift 4 通过表示 $0, $1, $2 --- $n 方便用户将内联闭包表示为速记参数名称。
    当我们在闭包表达式中表示速记参数名称时,定义部分省略了闭包参数列表。根据函数类型,将派生速记参数名称。由于速记参数是在表达式主体中定义的,因此省略了 'in' 关键字。
  • 作为运算符函数的闭包

    Swift 4 提供了一种简单的方法来访问成员,只需提供操作符函数作为闭包。在前面的示例中,当字符串相等时,关键字“Bool”用于返回“true”,否则返回“false”。
    闭包中的运算符函数使表达式变得更加简单 -
    
    let numb = [98, -20, -30, 42, 18, 35]
    var sortedNumbers = numb.sorted ({
       (left: Int, right: Int) -> Bool in
       return left < right
    })
    let asc = numb.sorted(<)
    print(asc)
    
    当我们使用操场运行上述程序时,我们得到以下结果 -
    
    [-30, -20, 18, 35, 42, 98]
    
  • 尾随闭包

    将函数的最终参数传递给闭包表达式是在“尾随闭包”的帮助下声明的。它用 {} 写在函数 () 之外。当无法在一行中编写内联函数时,需要使用它。
    
    reversed = sorted(names) { $0 > $1}
    
    其中 {$0 > $1} 表示为在(名称)之外声明的尾随闭包。
    
    import Foundation
    var letters = ["North", "East", "West", "South"]
    let twoletters = letters.map({ 
       (state: String) -> String in
       return state.substringToIndex(advance(state.startIndex, 2)).uppercaseString
    })
    let stletters = letters.map() { 
       $0.substringToIndex(advance($0.startIndex, 2)).uppercaseString 
    }
    print(stletters)
    
    当我们使用操场运行上述程序时,我们得到以下结果 -
    
    [NO, EA, WE, SO]
    
  • 捕获值和引用类型

    在 Swift 4 中,捕获常量和变量值是在闭包的帮助下完成的。即使变量不再存在,它也会进一步引用和修改闭包体内的那些常量和变量的值。
    捕获常量和变量值是通过在其他函数体中编写函数来使用嵌套函数实现的。
    嵌套函数捕获 -
    • 外部函数参数。
    • 捕获在外部函数中定义的常量和变量。
    在 Swift 4 中,当在函数内部声明常量或变量时,闭包也会自动创建对该变量的引用。它还提供了将两个以上变量引用为相同闭包的工具,如下所示 -
    
    let decrem = calcDecrement(forDecrement: 18)
    decrem()
    
    这里 oneDecrement 和 Decrement 变量都将指向与闭包引用相同的内存块。
    
    func calcDecrement(forDecrement total: Int) -> () -> Int {
       var overallDecrement = 100
       func decrementer() -> Int {
          overallDecrement -= total
          print(overallDecrement)
          return overallDecrement
       }
       return decrementer
    }
    let decrem = calcDecrement(forDecrement: 18)
    decrem()
    decrem()
    decrem()
    
    当我们使用操场运行上述程序时,我们得到以下结果 -
    
    82
    64
    46
    
    当每次调用外部函数 calcDecrement 时,它都会调用 decrementer() 函数并将值递减 18,并在外部函数 calcDecrement 的帮助下返回结果。这里 calcDecrement 作为一个闭包。
    即使函数 decrementer() 没有任何参数,闭包默认情况下通过捕获其现有值来引用变量 'overallDecrement' 和 'total'。指定变量的值的副本与新的 decrementer() 函数一起存储。Swift 4 通过在不使用变量时分配和释放内存空间来处理内存管理功能。