29 11 2021

第九章、函数

        9.1 函数基本介绍

                函数是为完成某一功能的程序指令(语句)的集合,称为函数。在go中,函数分为自定义函数和系统函数。

        9.2 函数基本语法

                基本语法如下:   

                image.png

                案例:

                image.png

        9.3 go中的包

                9.3.1 包的基本概念

                go的每一个文件都是属于一个包的,也就是说go是以包的形式来管理文件和项目目录结构的

                9.3.2 包的引出

                在实际的开发中,我们往往需要在不同的文件中,去调用其他文件定义的函数,比如在main.go中去使用utils.go中的函数  

                9.3.3 包的原理

                包的本质:实际上就是创建不同的文件夹,来存放程序文件

                image.png

                

                image.png

                9.3.4 包的三大作用

                a、区分相同名字的函数、变量等标识符

                b、当程序文件较多时,可以很好的管理项目

                c、控制函数、变量等访问范围,即作用域

                9.3.5 打包基本语法

                package 包名

                9.3.6 引入一个包

                import "包的路径"

                9.3.7 包的快速入门,调用包中的函数

                案列:

                image.png


                image.png


                image.png

                9.3.8 包的注意事项和细节说明

                image.png


                image.png


                image.png

        9.4 函数的调用机制

                9.4.1 基本介绍

                image.png

                image.png

                9.4.2 golang中,函数调用机制的底层分析

                image.png

                1. 第一步,主函数n1赋值,主函数中去调用test()函数;在调用一个函数时,会给该函数分配一个新的空间,编译器会通过自身的处理让这个新的空间和其他栈的空间区分开来

                image.png

                2. 第二步,test()函数执行完毕,终端输出n1=11,编译器回收test()函数里面的变量;在每个函数对应的栈中,数据空间是独立的,不会混淆;当一个函数执行完毕,程序会销毁这个函数对应的栈空间

                image.png

                3. 第三步,main()函数也执行完毕,终端输出test()中的n1=11,main()函数的n1=10,编译器回收main()函数里面的n1变量

                image.png

                9.4.3 案例演示

                image.png

                9.4.4 函数中return 语句介绍

                image.png

        9.5 递归函数

                9.5.1 递归函数简介

                一个函数在函数体内又调用了本身,我们称为递归调用

                案例演示:

                image.png

                过程分析图:

                image.png

                递归调用的总结:

                image.png

                9.5.2 递归练习题

                练习1:请使用递归的方式,求出斐波拉契数    1,1,2,3,5,8,13,21...

                image.png

                练习2:习题如下

                image.png

        9.6 函数注意事项和细节讨论

                image.png

                image.png 

                image.png

                案例演示第6:

                image.png

                第一步、

                image.png

                第二步、

                image.png

                案例演示第6、第8:

                image.png

                案例演示第10:

                image.png

                案例11:

                image.png

                image.png

                案例演示第13:

                image.png

        9.7 init函数

                9.7.1 基本介绍

                每一个源文件都可以包含一个init函数,该函数会在main函数之前执行,被go运行框架调用,也就是说init函数会在main函数之前被调用

                9.7.2 案例演示

                image.png

                9.7.3 细节讨论

                a、如果一个文件同时包含init函数、main函数、全局变量定义,则执行的流程顺序是全局变量定义 -> init函数 -> main函数

                image.png

                a、init函数的主要作用,就是完成一些初始化工作

                案例如下:

                image.png

                image.png

                a、如果主函数main.go  和初始化函数init.go中都含有变量定义,执行的流程又是怎么样的呢?

                image.png

                image.png

        9.8 匿名函数

                9.8.1 基本介绍

                Go支持匿名函数,如果我们某个函数只希望使用一次,可以考虑使用匿名函数匿名函数也可以实现多次调用

                9.8.2 匿名函数使用方

                使用式1:

                在定义匿名函数时就直接调用这种方式匿名函数只能调用一次

                image.png

                使用式2:

                将匿名函数赋值给一个变量(函数变量),再通过该变量来调用匿名函数

                image.png

                9.8.3 全局匿名函数

                如果将匿名函数赋值给一个全局变量,那么这个匿名函数就是一个全局匿名函数

                image.png

                image.png

        9.9 闭包函数

                9.8.1 基本介绍

                闭包就是“一个函数”和“与其相关的引用环境”组合的“整体(实体)”

                9.8.2 案例演示1

                image.png

                对上面代码说明和总结:

                1、AddUpper()是一个函数,返回的数据类型是 func(int) int

                2、闭包的说明:返回的是一个函数, 返回的是这个匿名函数,但是和这个匿名函数引用到了函数外面的变量n,因此这个匿名函数就和n形成一个整体,构成闭包

                image.png

                3、可以这样理解:闭包是一个类,函数是操作,n是字段,函数和它使用到的n构成闭包

                4、当我们反复调用f函数时,因为n是初始化一次,因此每调用一次就进行累计

                5、我们要搞清楚闭包的关键,就是要分析出返回的函数它使用(引用)到哪些变量,因为函数和它引用到的变量共同构成闭包

                案例演示2

                image.png    

                代码说明:返回的匿名函数和makeSuffix(suffix string)的suffix变量组成一个闭包,因为返回的函数引用到suffix这个变量            

                闭包的好处:闭包可以把匿名函数引用到的变量保存(引用)下来,进行下次调用回

        9.10 函数中的defer

                9.10.1 基本介绍

                在程序中,程序员经常需要创建资源,(比如:数据库链接、文件句柄、锁等~),为了再函数执行完毕后,及时的释放资源,go的设计者提供defer延时机制

                9.10.2 案例说明

                image.png

                9.10.3 defer细节说明

                a、当go执行到一个defer时,不会立即执行defer后的语句,而是将defer后的语句压入到一个栈中,然后继续执行函数下一个语句

                b、当函数执行完毕以后,再从defer栈中依次从栈顶取出语句执行,注意:(入栈先入后出机制)

                c、在defer将语句入栈时,也会将相关的值拷贝同时入栈!!! 

                image.png

                d、函数中,defer的最佳实践!!!!!!!!!!

                image.png

                image.png

        9.11 函数参数的传递方式

                9.11.1 基本介绍

                值类型默认就是值传递,而引用类型参数默认就是引用传递

                其实,不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是值传递的是值的拷贝,而引用传递的是地址的拷贝,一般来说,地址拷贝效率高,因为数据量小,而值拷贝决定拷贝的数据大小,数据越大,效率越低

                9.11.2 值类型和引用类型

                值类型:基本数据类型int系列、float系列、bool、string、数组和结构体struct

                引用类型:指针、slice切片、map、管道chan、interface等都是引用类型

                image.png

                3)如果希望函数内的变量能改变函数外的变量,可以传入变量的地址,(&num),函数内以指针的方式操作变量

        9.12 变量作用域

                9.12.1 基本介绍

                a、函数内部声明/定义的变量叫局部变量,作用域仅限于函数内部 

                b、函数外部声明/定义的变量叫全局变量,作用域在整个包都有效,如果其首字母大写,在整个程序有效

                9.12.2 案例演示

                image.png

                注意:::

                image.png

                image.png