defer延迟函数
- defer只是延迟执行并非延迟调用
- defer将函数入栈,所以逆序执行
func main() {
test_defer()
}
func test_defer() {
a := 1
defer fmt.Println(a)
a++
defer fmt.Println("666")
}
# 输出
666
1
函数的本质
func main() {
// test_defer()
test_func()
}
func test_func() {
fmt.Printf("%T", test_func) // %T 是打印变量类型
}
# 输出
func()
参数不同变量类型也不同
func main() {
test_func()
}
func test_func2(a, b int, c string, d []int, e [][]int, f [2]float32) int {
return 1
}
func test_func() {
fmt.Printf("%T", test_func2)
}
# 输出
func(int, int, string, []int, [][]int, [2]float32) int
函数变量同样可以赋值
func test_func3(a, b int) int {
fmt.Println("a=", a, " b=", b)
return a + b
}
func test_func() {
// fmt.Printf("%T", test_func2)
var func3 func(int, int) int
func3 = test_func3
func3(1, 1)
}
# 输出
a= 1 b= 1
函数在Go语言中是复合类型,可以看做是一种特殊的变量
函数名(): 调用返回的结构
函数名: 指向函数体的内存地址,是一种特殊的指针变量
func test_func() {
// fmt.Printf("%T", test_func2)
var func3 func(int, int) int
func3 = test_func3
func3(1, 1)
fmt.Printf("typeof func3:%s \nvalueof func3:%d \nvalueof test_func3:%d", reflect.TypeOf(func3), reflect.ValueOf(func3), reflect.ValueOf(test_func3))
}
# 输出
a= 1 b= 1
typeof func3:func(int, int) int
valueof func3:17413952
valueof test_func3:17413952
回调函数
高阶函数:根据go语言的数据类型的特点,可以将一个函数作为另外一个函数的参数。
fun1(), fun2()
将fun1函数作为fun2这个函数的参数
fun2函数: 就叫做高阶函数,接收了一个函数作为参数的函数
fun1函数: 就叫做回调函数,作为另外一个函数的参数
func main() {
callback_test()
}
func callback_test() {
fmt.Println(oper(2, 1, add))
fmt.Println(oper(2, 1, sub))
}
func oper(a, b int, fun func(int, int) int) int { // 高阶函数
return fun(a, b)
}
func add(a, b int) int { // 回调函数
return a + b
}
func sub(a, b int) int {
return a - b
}
# 输出
3
1
闭包
一个外层函数中,有内层函数,该内层函数中,会操作外层函数的局部变量
并且该外层函数的返回值就是这个内层函数。
这个内层函数和外层函数的局部变量,统称为闭包结构
局部变量的生命周期就会发生改变,正常的局部变量会随着函数的调用而创建,随着函数的结束而销毁
但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还在继续使用
func main() {
closure_test()
}
func closure_test() {
r1 := increment()
fmt.Println("r1:", r1)
fmt.Println(r1())
fmt.Println(r1())
fmt.Println(r1())
r2 := increment()
fmt.Println("r2:", r2)
fmt.Println(r2())
fmt.Println(r2())
fmt.Println(r1())
}
func increment() func() int { // 返回值是一个函数
i := 0
fun := func() int {
i++
return i
}
fmt.Println("&i:", &i)
return fun
}
# 输出
&i: 0xc00001c088
r1: 0x2c9d80
1
2
3
&i: 0xc00001c0a8
r2: 0x2c9d80
1
2
4
可以看到r1和r2指向同一个地址
在r2被创建时,r1指向函数的内部变量一般应该被销毁,但是因为闭包节后,r1调用时所对应的变量i没有被销毁。可以看到两个i的地址是不一样的。