Go语言函数高级篇
- 1.高阶函数
- 函数作为参数
- 函数作为返回值
- 2.匿名函数
- 3.defer
- 4.内置函数
1.高阶函数
高阶函数分为函数作为参数和函数作为返回值两部分。
函数作为参数
函数可以作为参数:
package main
import "fmt"
func add(x, y int) int {
return x + y
}
func mul(x, y int) int {
return x * y
}
func calc(x, y int, op func(int, int) int) int {
return op(x, y)
}
func main() {
res := calc(10, 20, add)
fmt.Println(res) // 30
resP := calc(10, 20, mul)
fmt.Println(resP) // 200
}
函数作为返回值
函数也可以作为返回值:
package main
import (
"errors"
"fmt"
)
func add(x, y int) int {
return x + y
}
func mul(x, y int) int {
return x * y
}
func do(s string) (func(int, int) int, error) {
switch s {
case "+":
return add, nil
case "*":
return mul, nil
default:
return nil, errors.New("无法识别")
}
}
func main() {
f, err := do("+")
fmt.Println(err, f(10, 20)) // <nil> 30
f2, err2 := do("-")
fmt.Println(f2, err2) // <nil> 无法识别
}
2.匿名函数
函数当然还可以作为返回值,但是在Go语言中函数内部不能再像之前那样定义函数了,只能定义匿名函数。匿名函数就是没有函数名的函数,匿名函数的定义格式如下:
func(参数)(返回值){
函数体
}
匿名函数因为没有函数名,所以没办法像普通函数那样调用,所以匿名函数需要保存到某个变量或者作为立即执行函数:
package main
import "fmt"
func main() {
// 将匿名函数保存到变量
add := func(x, y int) {
fmt.Println(x + y)
}
// 调用匿名函数
add(10, 20) // 30
// 自执行函数:匿名函数定义完加()直接执行
func(x, y int) {
fmt.Println(x + y)
}(20, 20) // 40
}
3.defer
Go语言中的defer
语句会将其后面跟随的语句进行延迟处理。在defer
归属的函数即将返回时,将延迟处理的语句按defer
定义的逆序进行执行,也就是说,先被defer
的语句最后被执行,最后被defer
的语句,最先被执行。
package main
import "fmt"
func main() {
fmt.Println("开始")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("结束")
}
结果:
开始
结束
3
2
1
由于
defer
语句延迟调用的特性,所以defer
语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等👕
defer
执行时机
在Go语言的函数中return语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer
语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:
4.内置函数
panic/recover
Go语言中目前(Go1.12)是没有异常机制,但是使用panic/recover
模式来处理错误。 panic
可以在任何地方引发,但recover
只有在defer
调用的函数中有效。 首先来看一个例子:
package main
import "fmt"
func funcA() {
fmt.Println("func A")
}
func funcB() {
panic("panic in B")
}
func funcC() {
fmt.Println("func C")
}
func main() {
funcA()
funcB()
funcC()
}
输出:
func A
panic: panic in B
goroutine 1 [running]:
main.funcB(...)
D:/SystemData/mine/Go-Page/hello.go:10
main.main()
D:/SystemData/mine/Go-Page/hello.go:18 +0x66
Process finished with the exit code 2
程序运行期间funcB中引发了panic
导致程序崩溃,异常退出了。这个时候我们就可以通过recover
将程序恢复回来,继续往后执行。
package main
import "fmt"
func funcA() {
fmt.Println("func A")
}
func funcB() {
defer func() {
err := recover()
if err != nil {
fmt.Println("recover in B")
}
}()
panic("panic in B")
}
func funcC() {
fmt.Println("func C")
}
func main() {
funcA()
funcB()
funcC()
// func A
// recover in B
// func C
}
recover()
必须搭配defer
使用defer
一定要在可能引发panic
的语句之前定义