Go语言函数的进阶以及defer的使用

114 阅读2分钟

定义函数类型

用type定义

type calculation func(int, int) int

这样就定义好了一个calculation类型函数,后面的函数只要满足它的格式,那就是这个类型;可以和普通类型一样使用; 比如:

func add(x, y int) int {
	return x + y
}

func sub(x, y int) int {
	return x - y
}

上面两个函数都可以算calculation类型 我们可以像声明基本类型一样:

var c calculation
c = add

这里c就是add函数,可以像用add函数一样直接用就好了

函数作为参数

因为函数也可以是一种类型,它可以像基本类型那样进行使用

func add(x, y int) int {
	return x + y
}
func calc(x, y int, op func(int, int) int) int {
	return op(x, y)
}
func main() {
	ret2 := calc(10, 20, add)
	fmt.Println(ret2) //30
}

匿名函数

立即执行的函数,只调用一次的函数

func main() {
	// 将匿名函数保存到变量
	add := func(x, y int) {
		fmt.Println(x + y)
	}
	add(10, 20) // 通过变量调用匿名函数

	//自执行函数:匿名函数定义完加()直接执行
	func(x, y int) {
		fmt.Println(x + y)
	}(10, 20)
}

闭包

闭包指的是一个函数和与其相关的引用环境组合而成的实体。简单来说,闭包=函数+引用环境。包含了它外部作用域的一个变量

func adder() func(int) int {
	var x int
	return func(y int) int {
		x += y  // 包含了它外部作用域的一个变量
		return x
	}
}
func main() {
	var f = adder() // 这是f是adder的返回值func(int)int
	fmt.Println(f(10)) //10  把10传进去,执行的是adder return部分
	fmt.Println(f(20)) //30  
	fmt.Println(f(30)) //60

	f1 := adder()
	fmt.Println(f1(40)) //40
	fmt.Println(f1(50)) //90
}

变量f是一个函数并且它引用了其外部作用域中的x变量,此时f就是一个闭包。 在f的生命周期内,变量x也一直有效。

defer语句

defer 后面的语句会被延迟到最后调用,当有好几个先被defer时,defer的语句最后被执行,最后被defer的语句,最先被执行。 例如:

func main() {
	defer fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)
}

输出就是321

defer执行时机

return语句在底层不是原子操作,它分为给返回值赋值和RET指令两步。而defer语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:

image.png 图片来自七米老师的博客

这篇文章主要是我自己有一些比较不懂得地方,如要具体学习,可以参考七米老师的博客www.liwenzhou.com/posts/Go/09…