发布于 2015-06-14 01:43:56 | 225 次阅读 | 评论: 0 | 来源: 网络整理
如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。 尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。
func someFunctionThatTakesAClosure(closure: () -> ()) {
// 函数体部分
}
// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
// 闭包主体部分
})
// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
// 闭包主体部分
}
注意:
如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把()
省略掉。
在上例中作为sort
函数参数的字符串排序闭包可以改写为:
reversed = sort(names) { $0 > $1 }
当闭包非常长以至于不能在一行中进行书写时,尾随闭包变得非常有用。 举例来说,Swift 的Array
类型有一个map
方法,其获取一个闭包表达式作为其唯一参数。 数组中的每一个元素调用一次该闭包函数,并返回该元素所映射的值(也可以是不同类型的值)。 具体的映射方式和返回值类型由闭包来指定。
当提供给数组闭包函数后,map
方法将返回一个新的数组,数组中包含了与原数组一一对应的映射后的值。
下例介绍了如何在map
方法中使用尾随闭包将Int
类型数组[16,58,510]
转换为包含对应String
类型的数组["OneSix", "FiveEight", "FiveOneZero"]
:
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]
如上代码创建了一个数字位和它们名字映射的英文版本字典。 同时定义了一个准备转换为字符串的整型数组。
您现在可以通过传递一个尾随闭包给numbers
的map
方法来创建对应的字符串版本数组。 需要注意的时调用numbers.map
不需要在map
后面包含任何括号,因为其只需要传递闭包表达式这一个参数,并且该闭包表达式参数通过尾随方式进行撰写:
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"]
map
在数组中为每一个元素调用了闭包表达式。 您不需要指定闭包的输入参数number
的类型,因为可以通过要映射的数组类型进行推断。
闭包number
参数被声明为一个变量参数(变量的具体描述请参看常量参数和变量参数),因此可以在闭包函数体内对其进行修改。闭包表达式制定了返回类型为String
,以表明存储映射值的新数组类型为String
。
闭包表达式在每次被调用的时候创建了一个字符串并返回。 其使用求余运算符 (number % 10) 计算最后一位数字并利用digitNames
字典获取所映射的字符串。
注意:
字典digitNames
下标后跟着一个叹号 (!),因为字典下标返回一个可选值 (optional value),表明即使该 key 不存在也不会查找失败。
在上例中,它保证了number % 10
可以总是作为一个digitNames
字典的有效下标 key。
因此叹号可以用于强制解析 (force-unwrap) 存储在可选下标项中的String
类型值。
从digitNames
字典中获取的字符串被添加到输出的前部,逆序建立了一个字符串版本的数字。 (在表达式number % 10
中,如果number为16,则返回6,58返回8,510返回0)。
number
变量之后除以10。 因为其是整数,在计算过程中未除尽部分被忽略。 因此 16变成了1,58变成了5,510变成了51。
整个过程重复进行,直到number /= 10
为0,这时闭包会将字符串输出,而map
函数则会将字符串添加到所映射的数组中。
上例中尾随闭包语法在函数后整洁封装了具体的闭包功能,而不再需要将整个闭包包裹在map
函数的括号内。