Swift - 闭包


Swift 4 中的闭包类似于组织为块并在任何地方调用的自包含函数,如 C 和 Objective C 语言。函数内部定义的常量和变量引用被捕获并存储在闭包中。函数被认为是闭包的特殊情况,它采用以下三种形式 -

全局功能 嵌套函数 闭包表达式
有名字吧 不捕获任何值 有名字吧 从封闭函数中捕获值 未命名闭包捕获相邻块的值

Swift 4 语言中的闭包表达式遵循清晰、优化和轻量级的语法风格,其中包括。

  • 从上下文推断参数和返回值类型。
  • 从单表达式闭包隐式返回。
  • 速记参数名称和
  • 尾随闭包语法

句法

以下是定义闭包的通用语法,它接受参数并返回数据类型 -

{
   (parameters) −> return type in
   statements
}

以下是一个简单的例子 -

let studname = { print("Welcome to Swift Closures") }
studname()

当我们使用 Playground 运行上述程序时,我们得到以下结果 -

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)

当我们使用 Playground 运行上述程序时,我们得到以下结果 -

10

闭包中的表达式

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

升序程序

对字符串进行排序是通过标准库中已经提供的 Swift 4s 关键保留函数“sorted”来实现的。该函数将按升序对给定字符串进行排序,并返回新数组中的元素,其大小和数据类型与旧数组中提到的相同。旧数组保持不变。

排序函数内部表示两个参数 -

  • 已知类型的值表示为数组。

  • 数组内容(Int,Int)并返回布尔值(Bool),如果数组排序正确则返回 true 值,否则返回 false。

编写带有输入字符串的普通函数并将其传递给排序函数,以使字符串排序到新数组,如下所示 -

func ascend(s1: String, s2: String) -> Bool {
   return s1 > s2
}

let stringcmp = ascend(s1: "Swift 4", s2: "great")
print (stringcmp)

当我们使用游乐场运行上述程序时,我们得到以下结果 -

true

要为冰淇淋排序的初始数组给出为“Swift 4”和“great”。对数组进行排序的函数被声明为字符串数据类型,其返回类型被称为布尔值。对两个字符串进行比较并按升序排序并存储在新数组中。如果排序成功,该函数将返回 true 值,否则返回 false。

闭包表达式语法使用 -

  • 常数参数,
  • 可变参数,以及
  • 输入输出参数。

闭包表达式不支持默认值。可变参数和元组也可以用作参数类型和返回类型。

let sum = {
   (no1: Int, no2: Int) -> Int in 
   return no1 + no2 
}

let digits = sum(10, 20)
print(digits)

当我们使用 Playground 运行上述程序时,我们得到以下结果 -

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)

当我们使用 Playground 运行上述程序时,我们得到以下结果 -

[75, 20, 10, 5, -6]
[-6, 5, 10, 20, 75]

该语句本身明确定义了当 string1 大于 string 2 时返回 true,否则返回 false,因此这里省略了 return 语句。

已知类型的封闭件

考虑两个数字相加。我们知道加法将返回整数数据类型。因此已知的类型闭包被声明为 -

let sub = {
   (no1: Int, no2: Int) -> Int in 
   return no1 - no2 
}

let digits = sub(10, 20)
print(digits)

当我们使用 Playground 运行上述程序时,我们得到以下结果 -

-10

将简写参数名称声明为闭包

Swift 4 自动为内联闭包提供简写参数名称,可用于通过名称 $0、$1、$2 等引用闭包参数的值。

var shorthand: (String, String) -> String
shorthand = { $1 }
print(shorthand("100", "200"))

这里,$0 和 $1 指的是闭包的第一个和第二个字符串参数。

当我们使用 Playground 运行上述程序时,我们得到以下结果 -

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)

当我们使用 Playground 运行上述程序时,我们得到以下结果 -

[-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)

当我们使用 Playground 运行上述程序时,我们得到以下结果 -

[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()

当我们使用 Playground 运行上述程序时,我们得到以下结果 -

82
64
46

每次调用外部函数 calcDecrement 时,它都会调用 decrementer() 函数并将值递减 18,并在外部函数 calcDecrement 的帮助下返回结果。这里 calcDecrement 充当闭包。

即使函数 decrementer() 没有任何参数,默认情况下闭包也会通过捕获其现有值来引用变量“overallDecrement”和“total”。指定变量值的副本使用新的 decrementer() 函数存储。Swift 4 通过在变量不使用时分配和释放内存空间来处理内存管理功能。