异常处理

defer 通常用于延迟调用指定的函数。例如:

上例最终输出的结果是: “Hello World!”.

这是因为: 会在 outerFunc 退出之前执行打印操作,因此被 defer 调用的函数也称为“延迟函数”。

defer 常用场景
  1. // 使用 defer 关闭 http 请求响应体的 Body
  2. func closeBody(url string) error {
  3. resp, err := http.Get(url)
  4. defer resp.Body.Close()
  5. // ... do more stuff ...
  6. return err
  7. }
  1. // 使用 defer 关闭文件句柄
  2. func closeFile(filename string) error{
  3. f, err := os.Open(filename)
  4. // ... do more stuff ...
  5. return err
defer 使用中一些注意点
  • 例子1

请看以下例子,猜下输出结果是?

  1. func printNumber() {
  2. for i := 0; i<5; i++{
  3. defer func(){
  4. fmt.Println(i)
  5. }()
  6. }
  7. }

最终输出的结果是 5 5 5 5 5。 这是因为 defer 所调用的函数是延迟执行的。等到执行 defer 所调用的函数时,i 已经是 5 了。接着看下面这个例子:

  1. func printNum() {
  2. for i := 0; i < 5; i++ {
  3. defer func(v int) {
  4. fmt.Println(v)
  5. }(i)
  6. }

这个例子最终输出的是: 4 3 2 1 0。具体是什么原因留作大家思考。

  • 例子2

当程序遇到致命错误导致无法继续运行时就会出发 panic , 例如:数组越界,空指针等。

以下代码将会出发数组越界异常。

  1. s := []int{1, 2, 3}
  2. for i := 0; i <= 4; i++ {
  3. fmt.Println(s[i])
  4. }

上述例子中因为数组越界,触发了 runtime 异常,导致程序退出。在实际开发中,也可以主动调用 panic 函数达到同样效果。

  1. func panicFunc() {
  2. panic(errors.New("this is test for panic"))
  3. }

recover 函数返回的是一个 interfac{} 类型的结果,如果捕获到了 panic 事件,该结果就为非 nil。见下例:

  • 思考以下代码的输出,并解释为什么
  1. func printNumbers(){
  2. for i:=0; i<5; i++{
  3. defer func(n int){
  4. fmt.Printf(n)
  5. }(i * 2)
  6. }
  7. }