简单介绍:函数闭包、defer、panic、recover
这里记录的是我个人不太熟练的语法和知识
详细内容移步:李文周的博客(非常详细)
#闭包
首先介绍前提知识:
https://www.cnblogs.com/cxying93/p/6103375.html
1.变量作用域
函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。
2.如何从外部读取函数内部的局部变量?
在函数内部再定义一个函数。
“理论上” 匿名函数在函数f内部,此时函数f的所有局部变量对匿名函数都是可见的,但是匿名函数的局部变量对函数f是不可见的。
“但是” 匿名函数作为函数f的返回值,我们就可以在函数f这个“外部”读取到匿名函数的局部变量。
“等价于” 在闭包的情况下:
func main() {
a := f()
for i := 0; i < 10; i++ {
fmt.Println(a(1))
}
}
func f() func(int) int {
i := 0
return func(int) int {
i = i + 1
return i
}
}
3.闭包的概念
上述代码中的匿名函数,就是闭包。
闭包=函数+引用环境 or 闭包就是能够读取其他函数内部变量的函数 or 闭包可以理解成“定义在一个函数内部的函数”
4.闭包的用途
一个是读取函数内部的变量,另一个是让变量保持在内存,不会在调用函数f后被清除
5.闭包注意点
闭包会使得函数中的变量保存在内存中,滥用闭包会消耗很大内存。解决办法就是:在退出函数前,将局部变量删除
#defer
defer 延迟处理语句,被修饰的语句会被压栈,在函数执行到return之前,依次出栈执行。
https://www.liwenzhou.com/posts/Go/09_function/#autoid-2-4-2
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
x := 1
y := 2
defer calc("AA", x, calc("A", x, y))
x = 10
defer calc("BB", x, calc("B", x, y))
y = 20
}
A 1 2 3
B 10 2 12
BB 10 12 22
AA 1 3 4
上述代码需要注意:defer注册要延迟执行的函数时该函数所有的参数都需要确定其值。
也就是说:对应的参数要确定相应的值
例如:第一个defer语句压栈时,它最终输出是确定的。等价于,如果参数是函数,就必须将return值给计算出来。
#panic/recover
https://www.cnblogs.com/ghj1976/archive/2013/02/11/2910114.html
panic 关键点在于,当函数执行的时候panic掉了,不往下走了,这是会先等到defer,让defer跑完后才会传递panic。
recover 程序一旦panic掉了,就会走defer那里,我们就在defer里面调用recover函数捕获panic(如果有panic的话),被捕获的panic就不会传递,这样程序就可以继续执行。
https://www.liwenzhou.com/posts/Go/09_function/#autoid-2-4-2
所以recover必须搭配defer使用,因为recover需要捕获panic,所以搭配使用的defer语句要再可能触发panic之前定义。
func funcA() {
fmt.Println("func A")
}
func funcB() {
defer func() {
err := recover()
//如果程序出出现了panic错误,可以通过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
可能检查不够仔细,有错欢迎留言