Swift--闭包
-
闭包的概念
-
Swift闭包表达式
-
使用闭包返回值
-
使用尾随闭包
-
捕获上下文中的变量和常量
支持闭包有两个前提
1、支持函数类型,能够将函数作为参数或返回值传递。
2、支持函数嵌套。
概念
闭包:是自包含的匿名函数代码块,可以作为表达式、函数参数和函数返回值,闭包表达式的运算结果是一种函数类型。
Swift中的闭包类似于Objective-C中的代码块、C++和C#中的Lambda表达式、Java中的匿名内部类。
Swift闭包表达式-标准写法
{(参数列表) - > 返回值类型 in
语句组
}
标准形式的闭包
{(a: Int, b:Int)-> Int in
return a + b
}
//标准写法
func calculate2(opr: String)-> (Int, Int)->Int {
var result:(Int, Int) -> Int
switch (opr) {
case "+":
result = {
(a: Int, b: Int)-> Int in
return a + b
}
default:
result = {
(a: Int, b: Int) ->Int in
return a - b
}
}
return result
}
let f3: (Int, Int) -> Int = calculate2(opr: "+")
print("10 + 5 = \(f2(10, 5))" )
let f4: (Int, Int) -> Int = calculate2(opr: "-")
print("10 - 5 = \(f2(10, 5))")
Swift闭包表达式--类型推断简化
类型推断简化的闭包
{(a, b) in return a + b }
{a, b in return a + b } //参数列表括号也可以省略
//类型推断简化
func calculate3(opr: String)-> (Int, Int)->Int {
var result:(Int, Int) -> Int
switch (opr) {
case "+":
result = {
(a, b) in
return a + b
}
default:
result = { a, b in return a - b } //也可以写成一行
}
return result
}
let f5 = calculate3(opr: "+")
print("10 + 5 = \(f2(10, 5))" )
let f6: (Int, Int) -> Int = calculate3(opr: "-")
print("10 - 5 = \(f2(10, 5))")
Swift闭包表达式--隐藏return关键字
如果在闭包内部语句组只有一条语句, 如return a + b等,那么这种语句都是返回语句。前面的关键字return 可以省略,省略形式如下:
{a, b in a + b}
//隐藏return关键字
func calculate4(opr: String)-> (Int, Int)->Int {
var result:(Int, Int) -> Int
switch (opr) {
case "+":
result = {
(a, b) in
let c = a + b
print(c)
return c
}
default:
result = { a, b in a - b } //也可以写成一行
}
return result
}
let f7 = calculate4(opr: "+")
print("10 + 5 = \(f2(10, 5))" )
let f8: (Int, Int) -> Int = calculate4(opr: "-")
print("10 - 5 = \(f2(10, 5))")
Swift闭包表达式--省略参数名
屏幕快照 2019-10-02 下午10.26.29.png//省略参数名
func calculate5(opr: String)-> (Int, Int)->Int {
var result:(Int, Int) -> Int
switch (opr) {
case "+":
result = {
let c = $0 + $1
print(c)
return c
}
default:
result = { $0 - $1 } // $0 == a $1 == b
}
return result
}
let f9 = calculate5(opr: "+")
print("10 + 5 = \(f2(10, 5))" )
let f10: (Int, Int) -> Int = calculate5(opr: "-")
print("10 - 5 = \(f2(10, 5))")
使用闭包返回值
闭包表达式本质上是函数类型,是有返回值的,我们可以直接在表达式中使用闭包的返回值。重新修改add和sub闭包,示例代码如下:
//使用闭包返回值
let c1: Int = {(a: Int, b: Int) ->Int in
return a + b
}(120, 10)
print("120 + 10 = \(c1)")
let c2: Int = {(a: Int, b: Int)-> Int in
return a - b
}(120, 10)
print("120 - 10 = \(c2)")
注:理解闭包返回值,可以将闭包看成一个函数。如图所示把灰色部分替换为函数,那么函数调用时后面是小括号的参数列表。
使用尾随闭包
闭包表达式可以作为函数的参数传递,如果闭包表达式很长,就会影响程序的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。
//使用尾随闭包
func calculate6(opr: String, funN: (Int, Int)-> Int) {
switch (opr) {
case "+":
print("10 + 5 = \(funN(10, 5))")
default:
print("10 - 5 = \(funN(10, 5))")
}
}
calculate6(opr: "+", funN: {
(a: Int, b: Int)-> Int in return a + b
})
calculate6 (opr: "+") {
(a: Int, b: Int)-> Int in return a + b
}
calculate6(opr: "+") {
$0 + $1
}
calculate6(opr: "-", funN: {
(a: Int, b: Int)-> Int in return a - b
})
calculate6 (opr: "-") {
(a: Int, b: Int)-> Int in return a - b
}
calculate6(opr: "-") {
$0 - $1
}
注意:有一些窍门可以帮助我们判断是闭包还是函数,闭包中往往有一些关键字,例如in, 还有缩写参数$0, $1
...等,这些特征在函数中是没有的。
捕获上下文中的常量和变量
嵌套函数或闭包可以访问它所在上下文的变量和常量,这个过程称为
捕获值(capturing value)
。即便是定义这些常量和变量的原始作用域已经不存在,嵌套函数或闭包仍然可以在函数体内或闭包体内引用和修饰这些值。
用嵌套函数来捕获上下文中的变量和常量
//用嵌套函数来捕获上下文中的变量和常量
func makeArray()-> (String)->[String] {
var ary:[String] = [String]()
func addElement(element: String)->[String] {
ary.append(element)
return ary
}
return addElement
}
let f11 = makeArray()
print("---f11---")
print(f11("张三"))
print(f11("李四"))
print(f11("王五"))
let f12 = makeArray()
print("---f12---")
print(f12("刘备"))
print(f12("张飞"))
print(f12("关羽"))
嵌套函数对ary进行值的捕获之后,就会把上一次的值接着使用,这样的话ary里面的内容会被增加。
输出结果如下图:
image.png
//无嵌套函数时
func makeArray2(element:String)-> [String] {
var ary:[String] = [String]()
ary.append(element)
return ary
}
let f13 = makeArray2("张三")
print(f13)
let f14 = makeArray2("李四")
print(f14)
let f15 = makeArray2("王五")
print(f15)
无嵌套函数时,每次调用函数时ary都被重新初始化一次
输出结果如图:
image.png
用闭包来捕获上下文中的变量和常量
//用闭包来捕获上下文中的变量和常量
func makeArray3()-> (String)->[String] {
var ary:[String] = [String]()
// func addElement(element: String)->[String] {
// ary.append(element)
// return ary
// }
// return addElement
return {
(element: String) -> [String] in
ary.append(element)
return ary
}
}
let f16 = makeArray3()
print("---f16---")
print(f16("贾宝玉"))
print(f16("林黛玉"))
print(f16("薛宝钗"))
let f17 = makeArray3()
print("---f17---")
print(f17("曹操"))
print(f17("曹丕"))
print(f17("曹植"))
输出结果如下图:
image.png