函数function
-
Go函数不支持嵌套、重载和默认参数
-
但是支持以下特性
-
- 无需声明函数原型(C\C++需要)
-
- 不定长度变量参数
-
- 多返回值
-
- 命名返回值参数
-
- 匿名函数
-
- 闭包
-
定义函数使用关键字func,且左大括号不能另起一行
-
函数也可以作为一种类型使用
函数基本写法
func func01() { fmt.Println("package lesson file lesson/lesson09.go function func01")}
一般的函数参数
func func02(a int, b string) { fmt.Println("package lesson file lesson/lesson09.go function func02") fmt.Println("func get value [a]:", a, " [b]:", b)}
函数参数省略写法
func func03(a, b, c int) { fmt.Println("package lesson file lesson/lesson09.go function func03") fmt.Println("func get value [a]:", a, " [b]:", b, " [c]:", c)}
多返回值 - 建议使用这种
func func04() (int, int, int) { fmt.Println("package lesson file lesson/lesson09.go function func04") a, b, c := 1, 2, 3 return a, b, c}
多返回值省略写法
func func05() (a, b, c int) { fmt.Println("package lesson file lesson/lesson09.go function func05") a, b, c = 1, 2, 3 return}
不定长度变量参数
func func06(a ...int) { fmt.Println("package lesson file lesson/lesson09.go function func06") fmt.Println("[a]:", a, " [a.type]:", reflect.TypeOf(a))}
固定变量与不定长度变量参数混合使用
func func07(b string, a ...int) { fmt.Println("package lesson file lesson/lesson09.go function func07") fmt.Println("[b]:", b, " [a]:", a, " [a.type]:", reflect.TypeOf(a))}
不定长度变量的函数,不会对外发生变更
func func08(slice ...int) { fmt.Println("package lesson file lesson/lesson09.go function func08") fmt.Println("[slice]:", slice) slice[0] = 3 slice[1] = 4 fmt.Println("[slice]:", slice)}
定常Slice作为变量传入函数
// 定常的slice作为变量传入函数,会造成外部的slice发生变更
// 这种方式进行的拷贝是slice当中地址的拷贝,也就是说操作其中的数据直接产生影响func func09(slice []int) { fmt.Println("package lesson file lesson/lesson09.go function func09") fmt.Println("[func09.slice]:", slice) slice[0] = 3 slice[1] = 4 fmt.Println("[func09.slice]:", slice)}
引用类型的传递
func func10(a *int) { fmt.Println("package lesson file lesson/lesson09.go function func10") *a = 2 fmt.Println("[a.address]:", a, "[a.value]:", *a)}
函数名称作为变量
fmt.Println() fmt.Println("test func11") function01 := func01 function01()
匿名函数
fmt.Println() fmt.Println("test func12") function02 := func() { fmt.Println("package lesson file lesson/lesson09.go function Anonymous Function ") } function02()
闭包
func closure(x int) func(int) int { fmt.Println("[&x]:", &x) return func(y int) int { fmt.Println("[&x]:", &x) return x + y }}
闭包调用
// 闭包 fmt.Println() function03 := closure(10) fmt.Println(function03(1)) fmt.Println(function03(2))
defer
- defer的执行方式类似其他预演中的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行
- 即使函数发生严重错误也会执行
- 支持匿名函数的调用
- 常用语资源清理、文件关闭、解锁一级记录时间等操作
- 通过与匿名函数配合可在return之后修改函数计算结果
- 如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则则是引用某个变量的地址
defer倒序打印
func func11(){ fmt.Println("a") defer fmt.Println("b") defer fmt.Println("c")}
打印输出
acb
循环中使用defer
for index:=0; index < 3;index++ { defer fmt.Println("[index]:",index) }
输出
2,1,0
循环中对函数使用defer
这里实际是闭包,在func里面的index是引用,但是由于defer是在循环的最后进行引用,
for index := 0;index < 3;index++{ defer func() { fmt.Println("[index]:",index) }() // 调用这个函数 }
输出
3,3,3
panic/recover
panic/recover 可以理解为try catch
- Go没有异常机制,但是panic/recover模式来处理错误
- Panic可以在任何地方引发,但recover只有在defer调用的函数中有效
func defer04() { fmt.Println() fmt.Println("package lesson file lesson/lesson09.go function defer04") functionPrintA() functionPanicB() functionPrintC()}func functionPrintA() { fmt.Println("package lesson file lesson/lesson09.go function functionPrintA")}func functionPanicB() { // 在panic之前设置defer函数,才能够让defer被访问到 defer func() { if err := recover(); err != nil { fmt.Println("Recover in B") } }() panic("package lesson file lesson/lesson09.go panic functionPanicB")}func functionPrintC() { fmt.Println("package lesson file lesson/lesson09.go function functionPrintC")}
程序输出
package lesson file lesson/lesson09.go function defer04package lesson file lesson/lesson09.go function functionPrintARecover in Bpackage lesson file lesson/lesson09.go function functionPrintC
程序首先运行panic,出现故障,此时跳转到包含recover()的defer函数执行,recover捕获panic,此时panic就不继续传递.但是recover之后,程序并不会返回到panic那个点继续执行以后的动作,而是在recover这个点继续执行以后的动作,即执行上面的defer函数,输出1
课堂作业
分析以下程序输出结果
func homework() { fmt.Println("package lesson file lesson/lesson09.go function homework") var fs = [4]func(){} for index := 0; index < 4; index++ { defer fmt.Println("defer [index]:", index) defer func() { fmt.Println("defer_closure [index]:", index) }() fs[index] = func() { fmt.Println("closure [index]:", index) } } for _, f := range fs { f() }}
输出结果
package lesson file lesson/lesson09.go function homeworkclosure [index]: 4closure [index]: 4closure [index]: 4closure [index]: 4defer_closure [index]: 4defer [index]: 3defer_closure [index]: 4defer [index]: 2defer_closure [index]: 4defer [index]: 1defer_closure [index]: 4defer [index]: 0