作用:将表达示包装为闭包, 目的:选择性求值
例如,做一个身份验证的程序,验证规则如下:
- 指纹扫描通过,身份验证通过;
- 若指纹扫描不通过则进行面部扫描,
- 面部扫描通过,身份验证通过;
- 面部扫描不通过,叫保安;
第一版程序如下:
func openTheDoor(){
print("Identity verified, door is opened!")
}
func callGuard(){
print("Maybe bad guy comes, call the guard!")
}
func verifyidentity(scanFinger:Bool,scanFace:Bool){
if scanFinger {
openTheDoor()
return
}
if scanFace {
openTheDoor()
}else{
callGuard()
}
}
讨论:
swift 方法中的表达式都是要求值的,这中间有两个问题:
- 某些参数的值的获取很耗资源,但某些情况下我们不需要;
- 某些条件下,某些参数的获取不可行。
我们的情况下属于第二种(这里假定指纹扫描结果和面部扫描的结果都需要另外的函数执行并提供结果,可自行写一个简单程序),显然当指纹扫描已经通过了,毫无必要再进行面部扫描,而且很耗资源。怎么办?一个很自然的想法是,第二个参数做成一个闭包(注,闭包的值是明确的,但可以选择性执行)
func verifyidentity(scanFinger:Bool,scanFace:()->Bool){
if scanFinger {
openTheDoor()
return
}
if scanFace() {
openTheDoor()
}else{
callGuard()
}
}
可能的调用形式是这样的
verifyidentity(scanFinger(),scanFace:{scanFace()})
显然,如果 scanFinger()通过了,scanFace实际上没有被执行。但是,实在太丑了。
再进行改良,程序如下:
func verifyidentity(scanFinger:Bool,@autoclosure scanFace:()->Bool){
if scanFinger {
openTheDoor()
return
}
if scanFace() {
openTheDoor()
}else{
callGuard()
}
}
可能的调用形式是这样的
verifyidentity(scanFinger(),scanFace:scanFace())
世界清静了。
@autoclosure做了什么?它把一个形如 para:T
形式的参数自动包装成一个para: () -> T
形式的闭包,而其调用形式不变。(闭包是否执行,当然是看你的程序怎么写了,于是出现了选择性执行的说法)
什么时机用?参数的值可能用不上且其获取耗费资源或某情况下不可以获取时。
一些讨论
问题一,能否直接传入闭包——NO
问题二,能被哪些形式重载?
//1.
func verifyidentity(scanFinger:Bool,@autoclosure scanFace:()->Bool){
}
//2.
func verifyidentity(scanFinger:Bool,scanFace:Bool){
}
//3.
func verifyidentity(scanFinger:Bool,scanFace:()->Bool){
}
居然三种形式函数在 playground 中写的时候都可以通过,但在使用的时候报错。删除第二种这可以了,因为1和2在使用时不可区分。
这里有一个小把戏,如果你的波函数有一个@autoclosure的版本,又有一个接受闭包的版本,就好像这个参数既可以接受一个普通参数,又可以接受一个闭包。