golang中函数的几个细节

defer延迟函数

  1. defer只是延迟执行并非延迟调用
  2. 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的地址是不一样的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值