1.介绍 错误是指程序中出现不正常的情况,从而导致程序无法正常运行。Go
语言中没有try...catch
来捕获错误,而是通过defer+recover+panic
模式来实现捕捉错误信息。
2. error接口 2.1 语法 Go语言通过内置的错误类型提供了非常简单的错误处理机制,即error
接口。该接口的定义如下:
type error interface { Error() string }
2.2 函数返回错误 对于大多数函数,如果要返回错误,大致上都可以定义为如下模式,必须将error
作为多种返回值中的最后一个。
func Demo (参数列表...) (x T, err error ){ }
2.3 判断错误 在Go语言中处理错误的方式通常是将返回的错误与nil
进行比较。nil
值表示没有发生错误,而非nil
值表示出现错误。如果不是nil
,需打印输出错误。
x,err := Demo(参数列表...)if err != nil { }
2.4 创建error对象几种方式 常见的创建error对象的几种方式:
Go语言errors
包下的New()
函数可以返回error
对象。
使用fmt包下的Errorf()
函数。
package mainimport ( "errors" "fmt" )func main () { err := createError(1 ) printError(err) err2 := createError(2 ) printError(err2) }func printError (err error ) { if err != nil { fmt.Printf("err==> %v | err.Error() ==> %v | 类型==> %T \n" ,err,err.Error(),err) } }func createError (way int ) error { if way == 1 { return errors.New("方式一: 使用errors包下的New() " ) } else if way == 2 { return fmt.Errorf("方式二: 使用fmt包下的Errorf(...) ---> " ) } return nil }
3.自定义错误 3.1 自定义错误的实现步骤
定义一个结构体,表示自定义错误的类型。
让自定义错误类型实现error接口:Error() string
。
定义一个返回error
的函数。根据程序实际功能而定。
3.2 使用示例 package mainimport ( "fmt" "time" )type MyError struct { msg string t time.Time }func (m MyError) Error() string { return fmt.Sprintf("错误信息: %s 发生时间: %v" , m.msg, m.t) }func login (phone, pwd string ) (bool , error ) { if phone == "17600000111" && pwd == "123456" { return true ,nil } err := MyError{"账号密码错误!" , time.Now()} return false ,err }func main () { res,err := login("17600000111" ,"123789" ) if err != nil { fmt.Printf("登录失败--> %v T --> %T \n" , err.Error(), err) } else { fmt.Printf("登录成功 --> %v \n" , res) } res2,err2 := login("17600000111" ,"123456" ) if err2 != nil { fmt.Printf("登录失败--> %v T --> %T \n" , err2.Error(), err2) }else { fmt.Printf("登录成功 --> %v \n" , res2) } }
4.延迟函数(defer) 4.1 概念 关键字defer
用于延迟一个函数或者方法(或者当前所创建的匿名函数)的执行。defer语句只能出现在函数或方法的内部。
4.2 在函数中使用 在函数中可以添加多个defer
语句。如果有很多调用defer
,当函数执行到最后时,这些defer
语句会按照逆序执行(报错的时候也会执行),最后该函数返回。
package mainimport "fmt" func main () { defer defer1() defer defer2(4 ,6 ) defer defer2(40 ,60 ) defer func () { fmt.Println("匿名函数defer3...." ) }() for i:= 1 ; i<4 ; i++ { fmt.Println(i) } }func defer1 () { fmt.Println("函数defer1...." ) }func defer2 (a,b int ) { fmt.Printf("函数defer2....a=%d b= %d a+b=%d \n" ,a,b,a+b) }
defer语句经常被用于处理成对的操作,如打开-关闭、连接-断开连接、加锁-释放锁。特别是在执行打开资源的操作时,遇到错误需要提前返回,在返回前需要关闭相应的资源,不然很容易造成资源泄露等问题。
5.panic(崩溃) panic
让当前的程序进入恐慌,中断程序的执行。panic()
是一个内建函数,可以中断原有的控制流程。其功能类似于PHP
中的throw
。
5.1 造成panic的场景 1.数组访问越界 package mainimport "fmt" func main () { arr := [3 ]int {1 ,2 ,3 } fmt.Println(arr[3 ]) }
2.访问未初始化的指针或 nil 指针 package mainimport "fmt" func main () { var b *int fmt.Println(b) fmt.Println(*b) }
3.向已经 close 的 chan
(管道) 里发送数据 package mainfunc main () { var ch = make (chan int ,1 ) close (ch) ch <- 1 }
4.类型断言 package mainimport "fmt" func main () { var i interface {} = "hello" a := i.([]string ) fmt.Println(a) }
5.2 使用 package mainimport "fmt" func main () { throw("请求成功!" ,1 ) throw("请求失败!" ,0 ) }func throw (msg string ,code int ) { if code == 0 { panic ("报错信息: " + msg) } fmt.Println("正确输出:" + msg) }
6.recover(恢复) 6.1 介绍 Go
语言中没有try...catch
来捕获错误,一旦触发panic
就会导致程序崩溃。在Go
中是通过recover
让程序恢复。值的注意的是recover()必须在延迟函数(defer)中有效。
在正常的程序运行过程中,调用 recover()会返回 nil
,并且没有其他任何效果。如果当前的Goroutine
陷入恐慌,调用recover()
可以捕获panic()
的输入值,使程序恢复正常运行。
6.2 使用 package mainimport "fmt" func main () { defer func () { err := recover () msg := fmt.Sprintf("err信息: %v" ,err) if err != nil { fmt.Println(msg) } }() testPanic("请求失败" ) }func testPanic (err string ) { panic ("错误信息" + err) }