函数的基本概念
为完成某一功能的程序指令集合,称为函数,Golang中函数分为:系统函数、自定义函数
Golang函数基本语法
func 函数名(形参列表) (返回值类型列表) {
执行语句...
return 返回值1, 返回值2(可选)...
}
说明:
形参列表:表示函数的输入
函数中的语句:表示为了实现某一功能代码块
函数可以有返回值,也可以没有
函数调用过程

说明:
1、在调用一个函数时,会给该函数分配一个独立的新空间,编译器会把这个新空间和栈区的其它空间区分开
2、每个函数对应的栈中,数据空间是独立的,不会混淆
3、当一个函数执行完毕,程序会销毁这个函数对应的栈空间
函数参数传递方式
1、值类型:基本数据类型int系列、float系列、bool、string、数据、结构体struct
2、引用类型:指针、slice切片、map、管道chan、interface接口等
return语句
1、Go函数支持返回(return)多个值(这一点其它编程语言没有)
func 函数名(形参列表) (返回值类型1, 返回值类型2, 返回值类型3...) {
语句...
return 返回值1, 返回值2, 返回值3...
}
2、如果函数 return 返回多个值,接收时使用 _ 符号,就表示占位并忽略某个返回值

有一种极端的写法,可以忽略所有返回值,这种写法没实际意义,仅做说明

3、如果返回值只有一个 ,返回类型列表可以不加括号()

函数使用注意事项和细节讨论
1、函数的形参列表可以是多个,返回值列表也可以是多个
形参列表和返回值列表的数据类型,可以是值类型,也可以是引用类型

2、函数的命名遵循标识符命名规范,首字母不能数字,首字母小写该函数只能被本包文件使用(private),首字母可以被本包文件和其他包文件共同使用
3、函数中的变量是局部的,函数外不生效
4、各数据类型传值与修改的问题
⑴. 基本数据类型 和 数组 默认都是值传递,即进行值拷贝,在函数内修改,不会影响到原来的值

⑵. slice 和 map 是引用传递,在函数内修改,原来的值也会被修改

5、如果希望函数内的变量能修改函数外的变量(指值传递的数据类型),可以传入变量的地址,在函数内以指针的方式操作(效果类似引用)

6、Golang不支持函数重载

7、在Golang中,函数也是一种数据类型,可以将函数赋值给一个变量,该变量就是函数类型,且通过该变量可以对函数调用

8、既然函数是一种数据类型,所以函数可以做为另一个函数的形参被调用,这是一种高阶函数的特性

9、为了简化数据类型定义,Golang支持自定义数据类型(结构体),基本语法:
type 自定义数据类型名 数据类型 //相当于一个别名
比如:
type myInt int //这时 myInt 就等价于int来使用了

比如:
type getSum func(int, int) int //这时就等价于一个函数类型 func(int, int) int

10、Golang支持对函数返回值命名(注意函数内部直接对命名的变量使用等号“=”)

函数返回值的命名,return时可变换顺序,接收的顺序按实际return的顺序

注意:对返回值命名后,就等于声明了变量,若函数内部不再赋值,默认return各类型的零值

对返回值命名后,也能return其它变量,使用时,接收实际return的值

11、函数相同类型的参数,可以合并使用一个类型标识,返回值命名同样可以如此

12、Golang支持可变参数,格式
func 函数名(形参... 类型) { ... }
比如:支持0到多个参数
func myFun(args... int) {
}
支持1到多个参数
func myFun(um int, args... int) {
}
说明:可变参数的位置,必须放在形参的最后一个,可变参数(比如上面的args) 是 slice 切片,可通过 args[index] 访问各个值
举例:

init函数
每个 go 文件都可以包含一个 init 函数,该函数会在 main 函数执行前,被 Golang 运行框架调用,也就是说 init 会在 main 函数前被调用,通常可用来做初始化
案例:

如果一个文件包含全局变量定义、init函数、main函数,执行流程是:全局变量定义 -> init函数 -> main函数

init函数可以用来做一些初始化工作

如果文件自身和引入的文件都有变量定义和 init 函数,执行流程是:
引入文件的变量定义 -> 引入文件的init函数 -> 文件自身的函数定义 -> 文件自身的init函数

相同包里的不同文件,定义全局变量、init函数的执行顺序是:按照文件名首字母顺序,先依次定义全局变量,再执行 init 函数,最后执行 main 包中的定义变量、init函数、main函数

匿名函数
Golang支持匿名函数,匿名函数就是没有名字的函数,如果某个函数只希望使用一次,可以考虑使用匿名函数,匿名函数也可以实现多次调用
匿名函数的使用方式,通过案例说明,比如使用匿名函数求两个数的和


全局匿名函数
如果将匿名函数赋值给一个全局变量,那么这个匿名函数,就是全局匿名函数,可以在整个程序中使用

函数的defer
在函数中,程序员经常需要创建资源,比如数据库资源、文件句柄、锁等,为了在函数执行完毕后,及时释放资源,Go的设计者提供了defer延时机制
具体执行步骤:
1、当 go 执行到一个 defer 时,不会立即执行 defer 关键字后的语句,而是将 defer 后的语句压入到一个栈中(可以理解为 defer 栈),然后继续执行 defer 下面语句
2、当函数执行完毕后,再从 defer 栈中,按照先入后出的原则,依次取出语句并执行

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

defer 和 return 的执行顺序:
return 的值计算优先于 defer 执行,defer 执行优先于 return 的返回动作,一句话:defer 语句会在函数 return 返回前执行

defer 的最佳实践案例:关闭文件资源、释放数据库连接等
