错误处理和 Is 函数
Go 语言中的 errors 包中的 Is
函数会判断目标是否有相应的错误匹配的上,在我们上一节的例子中,从 getRecords
函数中返回 nowRows
错误,然后这个错误的字符串信息从 webService
函数中返回,如果使用上 Is
函数,判断有没有查询到数据,然后才返回 noRows
错误:
package main import ( "errors" "fmt" ) var noRows = errors.New("no rows found") func getRecords() error { return noRows } func webService() error { if err := getRecords(); err != nil { return fmt.Errorf("Error %s when calling DB", err) } return nil } func main() { if err := webService(); err != nil { if errors.Is(err, noRows) { fmt.Printf("The searched record cannot be found. Error returned from DB is %s\n", err) return } fmt.Println("unknown error when searching for records") return } fmt.Println("webService call successful") }
在上面的 main
函数中,我们利用 Is
函数检查这个错误是否包含 noRows
错误。
因为 if errors.Is(err, noRows)
并不满足,所以这个 if
块里并不会执行。为了使得这个错误生效,我们需要 webService
函数返回 noRows
错误时对其进行封装。
一种方法是在返回错误时使用 %w
格式指定符,而不是 %s
。因此,可以把返回错误的那一行代码修改为:
return fmt.Errorf("Error %w when calling DB", err)
这意味着新返回的错误包裹了原来的 noRows
,并且上述主函数 if
条件将成功生效,下面是修改的程序:
package main import ( "errors" "fmt" ) var errNoRows = errors.New("no rows found") func getRecords() error { return errNoRows } func webService() error { if err := getRecords(); err != nil { return fmt.Errorf("error %w when calling DB", err) } return nil } func main() { if err := webService(); err != nil { if errors.Is(err, errNoRows) { fmt.Printf("The searched record cannot be found. Error returned from DB is %s\n", err) return } fmt.Println("unknown error when searching for records") return } fmt.Println("webService call successful") }
运行结果:
$ go run . The searched record cannot be found. Error returned from DB is error no rows found when calling DB
As 函数
errors 包中的 As
函数尝试把输入的错误转换为目标错误类型。如果错误链中的任何一个错误与目标错误匹配,就返回 true。
package main import ( "errors" "fmt" ) type DBError struct { desc string } func (dbError DBError) Error() string { return dbError.desc } func getRecords() error { return DBError{ desc: "no rows found", } } func webService() error { if err := getRecords(); err != nil { return fmt.Errorf("Error %w when calling DB", err) } return nil } func main() { if err := webService(); err != nil { var dbError DBError if errors.As(err, &dbError) { fmt.Printf("The searched record cannot be found. Error returned from DB is %s", dbError) return } fmt.Println("unknown error when searching records") return } fmt.Println("webservice call successful") }
在上面的程序中,我们修改了 getRecord
函数,返回一个 DBError
类型的自定义错误。
在 main
函数中,我们试图将 webService()
函数调用返回的错误转换为 DBError
类型。if errors.As(err, &dbError)
语句将会成功,因为我们已经把错误包起来了。运行这个代码,将会返回:
The searched record cannot be found. Error returned from DB is no rows found
总结
程序可能会随时都会出现异常,需要我们在开发过程中提前做好异常处理。所以本文介绍了 Go 语言中的错误处理,Go 标准库提供的两种创建 error
的方式,并介绍了如何检查错误和如果传递错误。