Swift Closures(闭包)

Swift Closures(闭包)

Swift 4中的Closures(闭包)类似于组织为块的自包含函数,并且像C和Objective C语言一样调用。 在函数内定义的常量和变量引用被捕获并存储在闭包中。 函数可以看作是闭包的特殊情况,它采用以下三种形式 -

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

Swift 4语言中的Closures(闭包)表达式遵循清晰,优化和轻量级的语法风格,包括 -

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

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

{
   (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 4键保留函数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)

使用playground运行上述程序时,得到以下结果 -

true

要为icecream初始数组元素值为“Swift 4”“great”。 将数组排序的函数声明为字符串数据类型,返回类型称为布尔值。 两个字符串都按升序进行比较和排序,并存储在一个新数组中。 如果成功执行排序,则函数将返回true值,否则返回false值。

闭包表达式语法使用 -

  • 常数参数
  • 变量参数
  • inout参数

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

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

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

使用playground运行上述程序时,得到以下结果 -

50

函数语句中提到的参数和返回类型声明也可以用带有in关键字的内联闭包表达式函数表示。 声明参数和返回类型in关键字用于表示闭包的主体。

单表达式隐式返回

这里,sorted函数的第二个参数的函数类型清楚地表明闭包必须返回一个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大于string2时返回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引用闭包的第一个和第二个String参数。

使用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)

执行上面示例代码,得到以下结果 -

[-30, -20, 18, 35, 42, 98]

闭包尾随

在“Trailing Closures”的帮助下声明将函数的最终参数传递给闭包表达式。 它用{}写在函数()之外。 当无法在单行上内联编写函数时,需要使用它。

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

这里的forDecrementdecrem变量都指向与闭包引用相同的内存块。

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()不使用任何参数,默认情况下,闭包通过捕获其现有值来引用变量overallDecrementtotal。 指定变量的值副本与新的decrementer()函数一起存储。 Swift 4通过在不使用变量时分配和释放内存空间来处理内存管理功能。


以下是纠正/补充内容:

现在的Swift语法是 闭包中一定要加上by 啊,不然编译都过不了。就是 XXX.sortedby:提交时间:2019-09-03