swift-函数的高阶玩法

2021-01-27  本文已影响0人  Alex1989

函数可以赋值给变量也能作为函数(输入和输出

先来个低阶函数预热一下:

func testPrint(i: Int) {
    print("You print \(i)") //you print 3
}
testPint(i: 3)

把testPrint()作为变量使使:

func testPint(i: Int) {
    print("You print \(i)")
}

//第一种传参确定,如果是参数确定的,声明变量声明成函数类型()不加会报警告
var funVar: () = testPint(i: 4)
funVar = testPint(i: 5)

//第二种传参不确定,这种应用一般比较多
var funPar2 = testPint
funPar2(6)

把testPrint()作为方法参数玩玩:

let funVar3 = printInt
func useFunction(function:(Int)->()){
    function(7)
}
useFunction(function: printInt)
useFunction(function: funVar3)

函数声明:(Int)->(),左边括号是要传的参数,右边是返回值,上边测试是无返回值的。
再来一种有返回值的:

func returnFunc() -> (Int, Int) -> String {//函数嵌套
    return innerFunc
}
func innerFunc(i: Int, j: Int) -> String { //
    return "you input \(i)\(j)"
}
let tmpFun = returnFunc()
print(tmpFun) // function类型
var tmpStr = tmpFun(5, 8)//传入俩参数 返回 字符串
print(tmpStr)//you input 58

另一种写法:(可以把函数作为函数内部函数使用,不对外公开)

func returnFunc() -> (Int, Int) -> String {//函数嵌套
    func innerFunc(i: Int, j: Int) -> String { //
        return "you input \(i)\(j)"
    }
    return innerFunc
    
}

let tmpFun = returnFunc()
print(tmpFun) // function类型
var tmpStr = tmpFun(5, 8)//传入俩参数 返回 字符串
print(tmpStr)//you input 58

函数捕获函数外部变量

当函数引用了作用域之外的变量,这个变量就捕获了
下来看几个例子:

func counterFunc() -> (Int) -> String {
    var counter = 0
    func innerFunc(i: Int) -> String {
        counter += i // counter 被捕获
        return "Running total: \(counter)"
    }
    return innerFunc
}
print(counterFunc()(3))//打印3
print(counterFunc()(2))//打印2
/*
现在我们将删除函数作为变量使用
*/
let tmpFun = counterFunc()
print(tmpFun(1))//打印1
print(tmpFun(3))//打印4

一般来说,因为 counter 是 counterFunc 的局部变量,它在 return 语句执行之后就应该离开作用域并被摧毁。但因为 innerFunc 捕获了它,所以 Swift 运行时将一直保证它的存在,直到捕获它的函数innerFunc被销毁
我们可以看出多次调用innerFunc中,counter一直在叠加
调用tmpFun(3)的时候会生成捕获新的counter变量,此时在调用tmpFun(1)的时候counter 已被更新为1.

当我们从新声明一个函数变量,它会拥有属于自己的counter,和上边的互不影响

let tmp1Fun = counterFunc()
print(tmp2Fun(2))//打印2
print(tmp2Fun(2))//打印4
//再次调用
print(tmpFun(1))//打印5

闭包登场

可以将这些函数以及他们捕获的变量看作一个实例,这个类拥有一个单一的函数方法记忆变量(就是捕获的变量)
上述这种函数和捕获的变量组合起来称为闭包。tmpFun和tmp2Fun都是闭包。

函数可以使用func关键字创建,也可以使用{ }(花括号)来创建,这种方法可以称为匿名函数

//第一种写法
func doublerTest(i: Int) -> Int {
    return i * 2
}
[1,2,3,4].map(doublerTest)

//第二种写法 (匿名函数)
let doublerTest1 = {(i: Int) -> Int in
    return i * 2
}
[1,2,3,4].map(doublerTest1)

上述这两种出了传参的处理上略有不同,其实是完全等价的。

闭包的优势

简洁的语法:
[1,2,3,4].map{$0 * 2}//2,4,6,8
上述这样的方法完全等价于:doublerTest1这种写法。
简单讲讲这种写法的意思:
1.如果是一个很简单的表达式,可以直接传给就收Int的函数,而不需要将他存储到变量中。

2.如果编译器可以从上下文推断,就不需要声明参数了。

3.如果表达式只包括单一的可以不用填写return
[1, 2, 3].map( { i in i * 2 } )

4.swift为函数的参数自动提供简写形式,$0代表第一个参数,$1代表第二个参数

5.如果函数的最后一个参数是闭包表达式可以将闭包表达式移动函数调用的圆括号外部。使用花括号,这就是尾随闭包。
[1, 2, 3].map() { $0 * 2 }

6.如果函数表达式没有别的参数,调用的时候圆括号可以直接省略
[1, 2, 3].map { $0 * 2 }

以后会重点总结闭包。

上一篇 下一篇

猜你喜欢

热点阅读