Go defer panic recover

本文最后更新于:13 天前

1 defer 语句

Go 语言中的defer 语句会将其后面跟随的语句进行延迟处理,在defer语句的函数即将返回时候,将延迟处理的语句按照defer语句的逆序进行执行,也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行

1.1 defer 使用

package main

import "fmt"

func main() {
	fmt.Println("start")
	defer fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)
	defer fmt.Println(4)
	fmt.Println("over")
}
/*
start
over
4
3
2
1
*/

1.2 defer 命名返回值和匿名返回值

package main

import "fmt"

//调用方法 返回的值是0 : 匿名返回值
func f2()  int {
	var a int
	defer func() {
		a++
	}()
	return a
}
//调用方法 返回的值是1 : 命名返回值
func f3() (a int) {
	defer func() {
		a++
	}()
	return a
}
func main() {

	fmt.Println(f2())
}

1.3 defer 不太好理解的案例

package main

import "fmt"

func calc(index string,a,b int) int {
   ret := a + b
   fmt.Println(index,a,b,ret)
   return ret

}
//defer: defer在注册要延迟执行的函数时候, 该函数所有的参数都需要确定其值
func main() {
   a := 1
   b := 2
   defer  calc("addA",a,calc("A",a,b))
   a = 10
   defer  calc("addB",a,calc("B",a,b))
   b = 20

}
/*
注册顺序
   defer  calc("addA",a,calc("A",a,b))
   defer  calc("addB",a,calc("B",a,b))
执行顺序
   defer  calc("addB",a,calc("B",a,b))
   defer  calc("addA",a,calc("A",a,b))
 */
// 1. calc("A",a,b)  A 1 2 3
// 2. calc("B",a,b)  B 10 2 12
// 3. calc("addB",a,calc("B",a,b))  addB 10 12 22
// 4. calc("addA",a,calc("A",a,b))  addA 1 3 13   在addA之前定义了a:=1 所以函数参数已经注册生效

2 panic

panic 可以在任何地方引发 但是recover 只有在defer 调用的函数中有效

package main

import "fmt"

func fn1() {
	fmt.Println("f1")

}
func fn2() {
	panic("抛出一个异常")
}
func main() {
	fn1()
	fn2()   //程序执行到这里抛出异常,然后程序退出,不在往下执行
	fmt.Println("over...")
}
package main

import "fmt"

func fn1() {
	fmt.Println("f1")

}
func fn2() {
	defer func() {
		err := recover()
		if err != nil {
			fmt.Println("扑捉异常,输出错误,程序继续执行")
		}

	}()
	panic("抛出一个异常")
}
func main() {
	fn1()
	fn2()   //程序执行到这里抛出异常,然后程序退出,不在往下执行
	fmt.Println("over...")
}
/*
f1
扑捉异常,输出错误,程序继续执行
over...
*/

3 recover

recover 只有在defer 调用的函数中有效

package main

import "fmt"

func fn1(a,b int) int {
	defer func() {
		err := recover()
		if err != nil {
			fmt.Println("error: ",err)
		}

	}()
	return a/b   //除数为0,不符合语法报错,但是不影响程序继续执行
}

func main() {
	fmt.Println(fn1(10,0))
	fmt.Println("over")
}
/*
error:  runtime error: integer divide by zero
0
over
*/

4 defer panic recover 结合使用

package main

import (
	"errors"
	"fmt"
)

// error 也是一个数据类型
func readFile(path string) error {
	if path == "main.go" {
		return nil
	} else {
		return errors.New("文件不存在")
	}

}
func myFn() {
	defer func() {
		e := recover()
		if e != nil {
			fmt.Println("通知运维.文件不存在")
		}

	}()
	funcErr := readFile("xxx.go")
	if funcErr != nil {
		panic(funcErr)
	}
}
func main() {
	myFn()
	fmt.Println("继续执行。。。")
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!