美文网首页
swift初探之闭包

swift初探之闭包

作者: 皇军让我给你捎个话 | 来源:发表于2020-12-07 10:15 被阅读0次

    闭包定义:一个函数和它捕获的变量、常量环境组合起来,称为闭包。(但是好多人会把闭包表达式简称闭包,但是其实是两回事)

    1、一般指定义在函数内部的函数

    2、一般捕获的是外层函数的局部变量、常量

    我们在函数里面定义一个函数,使用汇编看一看内层函数是怎样捕获外层函数的局部变量

    首先写一个函数里面嵌套一个函数里面的汇编是什么样

    定义一个函数嵌套函数,打上断点

    我们定义一个exec()函数返回值是一个()-> Int类型的函数,并且初始化一个函数,赋值个全局变量fn。

    断点定位位置

    上面的汇编可以看到是在exec()里面,首先我们要了解在汇编里面rax寄存器与rdx寄存器是作为函数的返回值,这里没有rdx,但是有edx。edx其实就是就是在rdx寄存器里面,rdx寄存器是64bit,edx是32bit。所以根据上面的可以看出rax里面放置的是我们定义sum的函数地址(右面的注释也是可以看出来的),edx里面放的是0,因为上面 做了异或的操作,异或相同的为0,所以ecx里面是0.把ecx放到rdx里面。

    放开断点进入到mian函数里面

    在控制台输入si一步一步就会到这里

    call是调用exec()函数使用rax寄存器、rdx寄存器作为返回参数,根据右面的注释可以看出来,rax寄存器里面的sum函数地址放入fn的内存中,rdx寄存器里面的内容放入到fn的后8个字节。所以fn的内存中存放的是sum的函数地址和8个0.

    这是普通的情况下,内部函数没有对外部函数的局部变量进行捕获。接下来举一个捕获的例子

    内层函数捕获外层函数的局部变量例子

    这个例子跟上一个例子有些不同,不同点在于num += 1写到了sum函数中,而且调用的三次fn(),在控制台可以看出打印的结果,是11、12、13。我对num并没有做什么,但是打印的结果是不一样的,这说明第二次调用的fn中的num是使用上一次fn中的num。

    在一个函数中局部变量是放在栈中,走到了最后一个大括号是会被释放掉。但是调用了几次num都是累加的,说明num是没有被释放掉。num应该是没有存放在栈中,但是应该存放在哪里呢

    下面我们来打个断点看一下汇编代码

    exec的汇编代码

    首先我们看一下函数的返回值,rax寄存器和rdx寄存器是函数的发返回参数,rax右面的主是可以看到是函数sum的地址值。

    exec的汇编代码

    rdx是从-0x10(%rbp)里面取的值,-0x10(%rbp)里面的值又是从allocObject里面返回的值,在程序里面,带alloc字样的注释,是从堆空间分配的内存空间。这里面看到立即数$0xa,这个就是我们初始化的10,存放到rax + 0x10的位置,有人就会问为什么会是加上0x10,而不是直接放到rax里面呢,因为在堆空间开辟的内存空间里是有16个字节是存放一些其他的信息,前8个字节是放的类型信息,后8个字节是存放的有关引用计数的信息。所以这里不难发现rdx里面存放的是num的内存地址。

    下面我们返回main函数看一下,exec()函数的返回值放到哪里

    main函数的汇编代码

    从汇编里面看rax里面的内容是放在fn的前8个字节里面,rdx的内容是放在fn的后8个字节里面。

    rax是存放的sum函数的函数地址,rdx是存放的num的堆空间的地址。

    总结:在内部函数没有使用外部函数的情况下,num是在栈空间里面存储,变量fn也不会对num进行存储。如果 内部函数对外部变量进行引用,num就会在堆空间进行开辟空间,内存地址由fn进行存储。闭包是通过新开辟了一个堆空间进行值的存储,把堆空间的地址值存放到变量的后八个字节中进行存储。

    相关文章

      网友评论

          本文标题:swift初探之闭包

          本文链接:https://www.haomeiwen.com/subject/ikhxwktx.html