1.只有defer
func Test1() {
defer fmt.Println("1")
defer fmt.Println("2")
}
//2
//1
2.defer+panic的时候
主程序语句+【go协程语句+协程defer+协程panic】
func test2() {
defer beego.Info("in main")
go func() {
defer beego.Info("in goroutine")
//主协程快太多,要是不等go协程,go协程里面连打印的代码都到不了,更不用说给机会运行到panic
beego.Error("22222222222222222222")
panic("恐慌打印...")
//根据多次实验:
//panic的执行在defer之后的,panic会让所有线程提前结束
}()
beego.Error("1111111111111111")
time.Sleep(1 * time.Millisecond)//让min等go协程
}
//2023/05/25 11:37:51.610 [E] 1111111111111111
//2023/05/25 11:37:51.610 [E] 22222222222222222222
//2023/05/25 11:37:51.631 [I] in goroutine
//panic: 恐慌打印...
3.defer + panic嵌套
// 恐慌嵌套
func test() {
defer beego.Info("in main")
defer func() {
beego.Info("in main2")
panic("panic again")//panic语句和普通语句不一样,需要把所有panic单独看成一个panic栈【入栈】
}()
panic("panic again2")//【再入栈】
}
//in main2
//in main
//panic again2
//panic again
4.defer + panic + recover
只有写在defer里面的recover可以有效终止恐慌
因为写在里面的捕获代码先于panic执行【recover相当于预埋一个报警处理】
func test6() {
defer func() {
if err := recover(); err != nil {
beego.Info("终止恐慌成功,程序退出仅仅表现为打印提示")
}
}()
panic("恐慌发生")
}
5.defer + return
【return语句】【defer】【退出r】
func f1() (r int) {
defer func() {
r++ //匿名函数没有入参,那么就自动找外面有没有
}()
return 0
//return 0 语句要习惯性看成两部分,【退出 r=0】
//1.将r=0
//2.因为没有新r的出现,所以r++操作的就是1
//3.return r
}
//1
func f2() (r int) {//函数一开始指定的返回值接收是r,那么就只能是r
t := 5
defer func() {
t = t + 5
}()
return t//很具有迷惑性,实际这里的t只是一个赋值作用
//1.t=5
//2.执行【return语句】r=t 所以r此时为5
//3.t=5+5 所以t此时为10
//4.return r
}
//5
func f3() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
//1.执行【return语句】r=1
//2.1传给匿名函数的后面括号里
//3.r=1+5 所以此时r为6【但是注意的是这个r是defer匿名函数重新定义成了自己的局部变量的】
// 所以6只在defer里面有效,也就导致后面返回值返回r可定不是6
//4.return r
}
//小范围可使用大范围变量值,反过来不行
//即:小用大,大不用小
//1