函数
Go 函数不支持嵌套,重载和默认参数
但支持以下特性:
- 无需声明原型,不定长度变参,多返回值,命名返回值参数,匿名函数,闭包
 
定义函数使用关键字func,且左大括号不能另起一行
函数也可以作为一种类型使用
无需声明原型
1  | func funcTest1(a int, b string) (int, string, int) {  | 
多参数同类型
参数
1  | func funcTest2(a, b, c int) {  | 
返回值
1  | func funcTest2(a, b, c int) (a1, b1, c1 int) {  | 
return与返回声明中的参数名一样就可以省略不用写,不过一般情况下,按照编码要求还是需要写得 
1  | func funcTest2(a, b, c int) (a1, b1, c1 int) {  | 
不定长度变参
java 中参数可变的例子
1  | private static int sumUp(int... values) {  | 
在go中也可以
1  | func funcTest3(a ...int) int {  | 
...[type]必须是最后一个参数,是一个slice
以下是错误的
1  | func funcTest(a ...int, b string)  | 
正确
1  | func funTest(b string, a ...int)  | 
...[type]可变参数可以看作是一个slice,但是与slice不同的是,不是引用类型,实际上得到是一个值拷贝。
如果参数是slice,是拷贝slice的内存地址,而不是值。
1  | func funcTest5(s []int) {  | 
输出
1  | before: [1 2 3]  | 
一般类型都是值拷贝,如果需要影响到传入的值,需要传入值的地址。
1  | - func funcTest5(s []int) {  | 
输出
1  | before: [1 2 3] 1  | 
函数也可以作为一种类型使用
这个特性与JavaScript中差不多,定义一个变量等于函数,使用这个变量相当于使用这个函数。在Go中一切皆类型
1  | func funcTest6() {  | 
输出
1  | hello everyone  | 
匿名函数
1  | func main() {  | 
没有命令函数名称。是一个代码块。
闭包
1  | func funcTest7(x int) func(int) int {  | 
输出
1  | func test 7 10 0xc00001a098  | 
3次输出x的地址是一样的。
defer
执行方式类似其他语言中的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行(先进后出,栈堆)。即使函数发生严重错误也会执行,支持匿名函数的调用。通常用于资源清理,文件关闭,解锁以及记录时间等操作。通过与匿名函数配合可在return之后修改函数计算结果。如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则引用某个变量的地址。。
Go 中没有异常机制,但是有 panic/recover模式来处理错误
panic可以在任何地方引发,但是recover只有在defer调用的函数中有效
相反顺序
1  | func main() {  | 
输出
1  | a  | 
按照调用顺序的相反顺序逐个执行
1  | func main() {  | 
输出
1  | 2  | 
闭包
在这个匿名函数中,i被当作一个地址的引用,引用这个局部变量,当循环结束时,i = 3 。在main函数结束后,开始执行defer中的代码。
1  | for i := 0; i < 3; i++ {  | 
输出
1  | 3  | 
可以改成这样:
1  | for i := 0; i < 3; i++ {  | 
输出
1  | 2  | 
panic
1  | func funcTest8(){  | 
输出
1  | func test 8  | 
并没有继续往下执行到test10
recover()
1  | func funcTest9() {  | 
需要在panic前面加入以上代码,输出
1  | func test 8  | 
练习
1  | func main() {  | 
输出
1  | closure i = 4  | 
fs[i]() 中的i,因为使用的是外部的i,实际上调用外部 i的地址,当循环体结束时,i = 4 ,所以输出closure i =  4
defer 使用的匿名函数与上面一样,是闭包的思想。