Swift学习之闭包

版权声明:不积跬步无以至千里,不积小流无以成江海! https://blog.csdn.net/Bolted_snail/article/details/87607679

闭包的定义

  • 一门语言要支持闭包有两个前提:
    1. 支持函数类型,能够将函数作为参数或返回值传递
    2. 支持函数嵌套。
  • 这两个前提Swift都满足,Swift中闭包的定义:闭包是自包含的匿名函数代码块,可以作为表达式,函数参数,函数返回值,闭包表达式的运算本质是一种函数类型。
  • 闭包表达式标准语法格式
{(参数列表) -> 返回值类型 in
    语句组
}
func calculate(opr:String) -> (Int,Int) -> Int {
    var result: (Int,Int)->Int
    switch opr {
    case "+":
        result = {
            (a:Int,b:Int) -> Int in
            return a + b
        }
    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 addClosure = calculate(opr: "+")
print("6+6 = \(addClosure(6, 6))")
let subClosure = calculate(opr: "-")
print("6-6 = \(subClosure(6,6))")

addClosure常量其实是calculate里面加法计算的闭包,subClosure是里面的加法计算的闭包,在调用是参数没有标签,因为addClosure返回的函数类型只有参数和返回值类型(也不允许添加参数标签),所以在闭包调用表时参数不带提示,所以闭包是自包含的匿名代码块,闭包本质上函数类型。

闭包简化

  • 上面示例是闭包的标准形式
 {
  (a:Int,b:Int) -> Int in
  return a + b
 }
  • 类型推断简化,Swift能推断参数a,b都是Int类型,返回值也是Int乐行,所以可以去掉类型,简化如下:
 {(a,b) in return a + b }

参数列表括号也可以省略:

 {a,b in return a + b }
  • 隐藏return关键字:如果闭包内部语句组只有一条语句,如return a + b,那么这种语句都是返回语句,前面的关键字 return可以省略:
{a, b in a + b}

省略的前提是闭包中只有一条return语句。

  • 省略参数名:Swift提供了参数名省略功能,我们可以用$0、$1、$2…来指定闭包中的参数。$0指代第一个参数, 1 1指代第二个参数,以次类推 n指代第n+1个参数。
func calculate2(opr:String) -> (Int,Int) -> Int {
    var result: (Int,Int)->Int
    switch opr {
    case "+":
        result = {$0+$1}
    default:
        result = {$0-$1}
    }
    return result
}
let addf = calculate(opr: "+")
print(addf(9,9)) // 18

闭包使用

  • 使用闭包返回值(使用闭包定义一个常量或变量): 闭包的本质是函数类型,是有返回值的,我们可以直接在表达式中使用闭包的返回值
let f1: (Int,Int)->Int = {$0 + $1}
print(f1)
let v1 = f1(1,2)
print(v1)
let v2 = {$0 + $1}(1,2)
print(v2)

f1常量是一个参数我连个Int 类型,返回值为两个参数和的闭包,是一个函数,v1是这个闭包被传参调用,v2是在定义了闭包的痛是给闭包传参调用。所以f1是闭包类型(函数类型),v1,v2是Int类型。

  • 闭包作为函数参数:
//加法闭包
let f1: (Int,Int)->Int = {$0 + $1}
//加法闭包
let f2: (Int,Int)->Int = {$0 - $1}
func calculate3(funcName:(Int,Int)->Int,a:Int,b:Int) ->Int{
    return funcName(a,b)
}
//闭包作为函数参数调用
//加法
print("3+2=\(calculate3(funcName: f1, a: 3, b: 2))") //3+2=5
//减法
print("3-2=\(calculate3(funcName: f2, a: 3, b: 2))") // 3-2=1

闭包f1,f2做参数传给函数调用。

  • 闭包作为函数返回值:
func calculate2(opr:String) -> (Int,Int) -> Int {
    var result: (Int,Int)->Int
    switch opr {
    case "+":
        result = {$0+$1}
    default:
        result = {$0-$1}
    }
    return result
}
let addf = calculate(opr: "+")
print(addf(9,9)) // 18

尾随闭包

  • 尾随闭包就是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。
func calculate4(a:Int,b:Int,funcName:(Int,Int)->Int) ->Int{
    return funcName(a,b)
}
//一般简写写法
let va1 = calculate4(a: 5, b: 6, funcName: {$0+$1})
//尾随闭包简写写法
let va2 = calculate4(a: 5, b: 6){$0+$1}

print(va1,va2)

注意尾随闭包,必须是闭包作为函数的最后一个参数,不是最后一个参数不能用尾随闭包写法。

闭包捕获上下文中的变量和常量

  • 嵌套函数或闭包可以访问它所在上下文的变量和常量,这个过程称为捕获值,即使是定义这些常量和变量的原始作用域已经不存在了,嵌套函数或闭包仍然可以在函数或闭包体内引用和修改这些值。
//捕获上下文变量和常量
func makeArr() -> (String) ->Array<String> {
    var arr:[String] = [String]()
    return{
        (item:String) ->[String] in
        arr.append(item)
        return arr
    }
}
let func1 = makeArr()
print(func1("张三"))
print(func1("李四"))
print(func1("王五"))
let func2 = makeArr()
print(func2("张3"))
print(func2("李4"))
print(func2("王5"))
print(func2("宋6"))

闭包捕获上下文中的变量和常量
理论上在makeArr调用完后,里面的变量arr做作用域已经没了,如果没给其他变量赋值,arr就销毁了。但从打印结果来看arr并没有销毁。这是因为arr变量相对于闭包而言,是一个上下文变量,因为arr在闭包中被使用和返回,所以闭包每次调用的时候,表里arr都能够被保持。func1,func2是makeArr被调用时返回的闭包,makeArr就相应的创建了两个可变数组arr,这个两个可变数组的真实作用域跟func1,func2是一致的。

  • 判断是闭包还是函数:闭包中往往有一些关键字,如 in,还有缩写参数$0,$1等等,这些特征函数是没有的。

猜你喜欢

转载自blog.csdn.net/Bolted_snail/article/details/87607679
今日推荐