defer的用法——为什么recover一定要写在defer后面的匿名函数里

70 阅读1分钟

代码1

package main

import "fmt"

func main() {
	fmt.Println("a")
	defer recover()
	panic("b")
	fmt.Println("c")
}

//输出:
//a
//panic: b

代码2

package main

import "fmt"

func main() {
   fmt.Println("a")
   defer func() {
      recover()
   }()
   panic("b")
   fmt.Println("c")
}

//输出:
//a

其中代码1捕获失败,代码2捕获成功,原因是因为直接调用在defer压入栈时已经调用过recover了,也就是说被压入栈时,recover并没有捕获到panic,自然也不会弹出时有什么作为。下面的代码3就是很好的例子

代码3

package main

import "fmt"

func main() {
	i := 0
	defer fmt.Println("第一个defer", i)
	defer func() {
		fmt.Println("第二个defer", i)
	}()
	i = 2
}

//输出:
//第二个defer 2
//第一个defer 0

下面则是一些其他情况的defer

1.defer放在panic后面是无法执行的

package main

import "fmt"

func main() {
	fmt.Println("a")
	panic("b")
	defer func() {
		recover()
	}()
	fmt.Println("c")
}

//输出:
//a
//panic: b

2.同样放在return后面也无法执行

package main

import "fmt"

func main() {
	fmt.Println("a")
	return
	defer func() {
		recover()
	}()
	panic("b")
	fmt.Println("c")
}

//输出:
//a