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 4中提供的关键字保留函数”sorted”可以实现字符串的排序,该函数已经在标准库中可用。该函数将给定的字符串以升序排序,并返回一个新数组,新数组中的元素与旧数组中的元素具有相同的大小和数据类型。旧数组保持不变。
排序函数中包含两个参数−
- 已知类型的值表示为数组。
-
数组内容 (Int, Int) 并返回一个布尔值 (Bool),如果数组已经正确排序,则返回true;否则返回false。
一个正常的包含输入字符串的函数被编写并传递给sorted函数,以便将字符串排序为新数组,如下所示−
func ascend(s1: String, s2: String) -> Bool {
return s1 > s2
}
let stringcmp = ascend(s1: "Swift 4", s2: "great")
print (stringcmp)
当我们在playground上运行上述程序时,我们会得到以下结果−
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’关键字就用于表示闭包的主体。
单表达式隐式返回
在这里,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分别指向闭包的第一个和第二个字符串参数。
当我们使用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通过在变量不使用时分配和释放内存空间来处理内存管理函数。