知识点:
1.异常处理 defer,panic,recover
2.error
3.自定义错误类型
异常处理:
在异常处理方面,Go语言不像其他语言,使用try..catch.. finall…, 而使用defer, panic, recover,将异常和控制流程区分开。即通过panic抛出异常,然后在defer中,通过recover捕获这个异常,最后处理。
但是更加推荐的错误处理方法:
Golang中我们通常会在函数或方法中返回error
结构对象来判断是否有异常出现,并且可以更具需要自定义各种类型的error。如果返回的 error 值为 nil,则表示未遇到错误,否则 error 会返回一个字符串,用于说明遇到了什么错误。
type error interface { Error() string}golang 中内置的错误类型 error 是一个接口类型,自定义的错误类型必须实现 Error()方法
如何生成error?
方式一:New方法 原生
将字符串 text 包装成一个 error 对象返回
func New(text string) error { return &errorString{text}}//例如var ErrShortWrite = errors.New("short write")
方式二:定义自己的错误
package mainimport ( "fmt" "time")// MyError is an error implementation that includes a time and message.type MyError struct { When time.Time What string}func (e MyError) Error() string { return fmt.Sprintf("%v: %v", e.When, e.What)}func oops() error { return MyError{ time.Date(1989, 3, 15, 22, 30, 0, 0, time.UTC), "the file system has gone away", }}func main() { if err := oops(); err != nil { fmt.Println(err) }}
defer:
defer是
Go语言中的延迟执行语句
,用来添加函数结束时执行的代码,常用于释放某些已分配的资源、关闭数据库连接、断开socket连接、解锁一个加锁的资源。
(1)defer执行顺序:
return xxx:赋值指令 + CALL defer指令 + RET指令return xxx会被改写成:返回值 = xxx调用defer函数空的return
整个return过程,没有defer之前,先在栈中写一个值,这个值会被当作返回值,然后再调用RET指令返回。return xxx语句汇编后是 1.先给返回值赋值,2.再做一个空的return,( 赋值指令 + RET指令)。defer的执行是被插入到return指令之前的,有了defer之后,就变成了(赋值指令 + CALL defer指令 + RET指令)。
而在CALL defer函数中,有可能将最终的返回值改写了…也有可能没改写。总之,return xxx不是一条原子指令,如果返回值改写了,那么看上去就像defer是在return xxx之后执行的~
example1
func f() (result int) { defer func() { result++ }() return 0}返回值:1
example2
func f() (r int) { t := 5 defer func() { t = t + 5 }() return t}返回值:5
example3
func f() (r int) { defer func(r int) { r = r + 5 }(r) return 1}返回值:1
example4
func f() (r int) { return 1 defer func() { r++ r++ }() return 2}返回值:1注意:如果去掉了return 2,会出现语法错误:Missing return at the end of function
example5
func main() { for i:=0 ;i<5; i++ { defer func() { fmt.Println(i) }() } fmt.Println("test:")}输出:test:55555func main() { for i:=0 ;i<5; i++ { defer func(i int) { fmt.Println(i) }(i) } fmt.Println("test:")}输出:test:43210
(2)defer栈
如果一个函数中有多个defer语句,它们会以LIFO(后进先出)的顺序执行。哪怕函数或某个延迟调用发生错误,这些调用依旧会被执。
package main //必须import "fmt"func test(x int) { result := 100 / x fmt.Println("result = ", result) defer fmt.Println("three")}func main() { defer fmt.Println("one") defer fmt.Println("two") //调用一个函数,导致内存出问题,除数不能为0 defer test(0) defer fmt.Println("four")}注:defer 需要放在 panic 之前定义,因为由panic引发异常以后,程序停止执行,即不再执行下面代码,放在后面调用不了defer
输出结果:
panic:
当程序遇到致命错误导致无法继续运行时就会触发panic,例如:数据越界,空指针等。我们可以通过主动调用 panic() 函数,抛出致命的错误。
通过使用recover()函数,我可以捕获上述的错误异常
golang 的错误处理流程:当一个函数在执行过程中出现了异常或遇到
panic(),正常语句就会立即终止,然后执行 defer 语句,再报告异
常信息,最后退出 goroutine。如果在 defer 中使用了 recover()
函数,则会捕获错误信息,使该错误信息终止报告。
panic会在调用它的函数中向本层和它的所有上层逐级抛出,若一直没有recover将其捕获,程序退出后会产生crash。
例如:
package main //必须import "fmt"func test(x int) { defer func() { if err:=recover(); err!=nil{ fmt.Println(err) } }() result := 100 / x fmt.Println("result = ", result)}func main() { //调用一个函数,导致内存出问题,除数不能为0 test(0) defer fmt.Println("end")}输出:runtime error: integer divide by zeroend
注意:
1.defer要定义在panic之前
2.recover()的调用仅当它在defer函数
中被直接调用
时才有效。在正常的执行过程中,调用 recover 会返回 nil 并且没有其他任何效果.
参考:http://www.coder55.com/articl…
文章来源:智云一二三科技
文章标题:【go】异常处理
文章地址:https://www.zhihuclub.com/429.shtml