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,5]
array.map() { ($0%2) == 0 }

例子2:如果closure内容只是一个函数调用,可以进一步简化

let yy = radians.map() { sin($0) }
let yy = radians.map( sin )

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...