在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
闭包是自包含的函数代码块,可以在代码中被传递和使用。 Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 lambdas 函数比较相似。 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。
在函数 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:
Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下:
闭包表达式(Closure Expressions)嵌套函数 是一个在较复杂函数中方便进行命名和定义自包含代码模块的方式。当然,有时候撰写小巧的没有完整定义和命名的类函数结构也是很有用处的,尤其是在您处理一些函数并需要将另外一些函数作为该函数的参数时。 闭包表达式是一种利用简洁语法构建内联闭包的方式。 闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。 下面闭包表达式的例子通过使用几次迭代展示了 sorted 函数(The Sorted Function)Swift 标准库提供了 下面的闭包表达式示例使用 let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
该例子对一个 提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为 func backwards(s1: String, s2: String) -> Bool {
return s1 > s2
}
var reversed = sorted(names, backwards)
// reversed 为 ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
如果第一个字符串 ( 然而,这是一个相当冗长的方式,本质上只是写了一个单表达式函数 (a > b)。 在下面的例子中,利用闭合表达式语法可以更好的构造一个内联排序闭包。 闭包表达式语法(Closure Expression Syntax)闭包表达式语法有如下一般形式: { (parameters) -> returnType in
statements
}
闭包表达式语法可以使用常量、变量和 下面的例子展示了之前 reversed = sorted(names, { (s1: String, s2: String) -> Bool in
return s1 > s2
})
需要注意的是内联闭包参数和返回值类型声明与 闭包的函数体部分由关键字 因为这个闭包的函数体部分如此短以至于可以将其改写成一行代码: reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )
这说明 根据上下文推断类型(Inferring Type From Context)因为排序闭包函数是作为 reversed = sorted(names, { s1, s2 in return s1 > s2 } )
实际上任何情况下,通过内联闭包表达式构造的闭包作为参数传递给函数时,都可以推断出闭包的参数和返回值类型,这意味着您几乎不需要利用完整格式构造任何内联闭包。 单表达式闭包隐式返回(Implicit Return From Single-Expression Clossures)单行表达式闭包可以通过隐藏 reversed = sorted(names, { s1, s2 in s1 > s2 } )
在这个例子中, 参数名称缩写(Shorthand Argument Names)Swift 自动为内联函数提供了参数名称缩写功能,您可以直接通过 如果您在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。 reversed = sorted(names, { $0 > $1 } )
在这个例子中, 运算符函数(Operator Functions)实际上还有一种更简短的方式来撰写上面例子中的闭包表达式。 Swift 的 reversed = sorted(names, >)
更多关于运算符表达式的内容请查看 运算符函数。 尾随闭包(Trailing Closures)如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。 尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。 func someFunctionThatTakesAClosure(closure: () -> ()) {
// 函数体部分
}
// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
// 闭包主体部分
})
// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
// 闭包主体部分
}
在上例中作为 reversed = sorted(names) { $0 > $1 }
当闭包非常长以至于不能在一行中进行书写时,尾随闭包变得非常有用。 举例来说,Swift 的 当提供给数组闭包函数后, 下例介绍了如何在 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 {
(var number) -> String in
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
// strings 常量被推断为字符串类型数组,即 String[]
// 其值为 ["OneSix", "FiveEight", "FiveOneZero"]
闭包 闭包表达式在每次被调用的时候创建了一个字符串并返回。 其使用求余运算符 (number % 10) 计算最后一位数字并利用
从
整个过程重复进行,直到 上例中尾随闭包语法在函数后整洁封装了具体的闭包功能,而不再需要将整个闭包包裹在 捕获值(Capturing Values)闭包可以在其定义的上下文中捕获常量或变量。 即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。 Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的函数体内的函数。 嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。 下例为一个叫做 func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
如果我们单独看这个函数,会发现看上去不同寻常: func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
由于没有修改 然而,因为每次调用该函数的时候都会修改
下面代码为一个使用 let incrementByTen = makeIncrementor(forIncrement: 10)
该例子定义了一个叫做 incrementByTen()
// 返回的值为10
incrementByTen()
// 返回的值为20
incrementByTen()
// 返回的值为30
如果您创建了另一个 let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven()
// 返回的值为7
incrementByTen()
// 返回的值为40
闭包是引用类型(Closures Are Reference Types)上面的例子中, 无论您将函数/闭包赋值给一个常量还是变量,您实际上都是将常量/变量的值设置为对应函数/闭包的引用。 上面的例子中, 这也意味着如果您将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包: let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// 返回的值为50
|
请发表评论