swift - closure
closure
closure是一种类似于函数的类型,也是first class type的一种。
closure是引用类型,有自己的指令和空间。
closure可以看作是一种轻量级的函数,它的一般格式如下:
//声明
let 名字 = {(参数) -> 返回值 in
closure的内容
}
//调用
let 返回值 = 名(参数)
//声明与调用合并使用
let 返回值 = {(参数) -> 返回值 in closure的内容}(实参)
closure参数的语法
有外参名
这种情况下closure与function的参数用法是一样的
func area(length l : Int, width w : Int) -> Int {
return l * w
}
let a = area(length : 2, width : 3)
let area{ (length l : Int, width w : Int) -> Int in
return l * w
}
let a = area(length : 2, width : 3)
无外参名
closure不需要通过_
来隐藏外参名
func area(length : Int, _width : Int) -> Int {
return length * width
}
let a = area(2, 3)
let area{ (length : Int, width : Int) -> Int in
return length * width
}
let a = area(2, 3)
看上去closure只是参数和返回值放在函数体里面的function?
NO!
swift的类型推导功能在closure上发挥得淋漓尽致。使得closure的语法更简洁易读。
类型推导
Void
假设c1是一个没有入参和返回值的closure,那么它应该这么写。
let c1 = {(_ : Void) -> Void in
...
}
事实上它可以写得更简洁:
(1)当closure的参数是Void类型时,可以省略不写
let c1 = {() -> Void in
...
}
(2)当closure的返回值是Void类型时,也可以省略不写
let c1 = { () in
...
}
(3)当closure的参数和返回值都是Void类型时,整体可以直接进入closure体
let c1 = { ... }
赋值
赋值表示式的一般格式为expression = value
在closure中,只要其中一方指明了类型,另一方的类型就可以自动推导出来
let tm = { () -> String in
...
return str
}
自动推导出tm的格式为() -> String
或者这样写:
let tm : () -> String = {
...
return str
}
这种情况下,就不需要写明closure表达式的参数和返回值了。
作为参数
假设有这样一个需求:
func bySquare(edge : Int) -> Int {
return edge * edge
}
func area(length : Int, calculate : Int -> Int) -> Int {
return calculate(length)
}
let a = area(5, calculate : bySquare)
这里使用了函数bySquare作为参数来决定使用什么方式计划面积。如果要使用closure bySquare作为参数,则应该这么写:
func area(length : Int,
bySquare : {(edge : Int) -> Int in
return edge * edge
}
)
(1)closure的内容只有一行,因此return可以去掉
func area(length : Int,
bySquare : {(edge : Int) -> Int in
edge * edge
}
)
(2)参数类型和返回值可以根据closure内容推导出来,所以可以省去。用’$’+’数字’代表使用的是第几个参数。
func area(length : Int,
bySquare : { $0 * $0 }
)
(3)因为closure是最后一个参数,因此可以使用trailing closure语法
func area(length : Int) { $0 * $0 } )
语句表达式
let area = {(r : Double) -> Double in
return 3.14 * r * r
}
可简化为:
let area = { 3.14 $0 * $0 }
语境
例子1:
let array = [1, 2, 3, 4, 5]
array.map( { (u:Int) -> Bool in
return (u%2) == 0
}
)
可简化为:
let array = [1, 2, 3, 4, 5]
array.map() { ($0%2) == 0 }
例子2:如果closure内容只是一个函数调用,可以进一步简化
let yy = radians.map() { sin($0) }
let yy = radians.map( sin )