Golang中的錯誤處理的示例詳解
本文介紹Golang錯誤處理機制,包括不同類型錯誤處理、定義運行時錯誤等內(nèi)容。
golang錯誤處理機制
Go錯誤處理類似C語言,沒有提供任何異常,以及類java語言使用的try/catch異常處理機制。go異常處理僅簡化為預(yù)定義的Error類型,Go沒有提供異常處理機制,不能拋出類似許多其他語言的異常。相反,Golang集成了新的錯誤處理機制,如panic 和 recovery。
error類型
error類型僅包括Error方法,返回string類型標(biāo)識具體的錯誤信息。代碼如下:
// The built-in error interface is a regular interface for handling errors.
// where nil means no errors.
type error interface {
Error() string
}
我們看到錯誤處理類型實際上是一個接口,包含一個簡單的error()方法,其返回值是一個字符串。通過定義可知:要實現(xiàn)錯誤處理,只需要向error()方法返回一個簡單的字符串。
示例
下面先看一個錯誤處理示例:
func main() {
conent, err := openFile()
if err != nil {
fmt.Println(err)
} else {
fmt.Println(string(conent))
}
}
只要 err!= nil (檢測到存在錯誤), 它將從執(zhí)行中終止,否則繼續(xù)正常的執(zhí)行流。
Go中很多函數(shù)返回多個值,通常其中一個返回值是錯誤類型。舉例: strconv.Atoi(),轉(zhuǎn)換字符串?dāng)?shù)據(jù)為數(shù)值類型,返回兩個值,第一個是轉(zhuǎn)換結(jié)果,第二個是錯誤。如果正常轉(zhuǎn)換,第二個返回值為nil。反之轉(zhuǎn)換失敗,可從錯誤中獲得錯誤原因。
下面示例檢查用戶輸入數(shù)據(jù)是否為數(shù)值,通過示例可以學(xué)習(xí)如何處理錯誤:
package main
import (
"fmt"
"strconv"
)
func main() {
var input string
fmt.Print("Type some number: ")
fmt.Scanln(&input)
number, err := strconv.Atoi(input)
if err == nil {
fmt.Println(number, "is number")
} else {
fmt.Println(input, "is not number")
fmt.Println(err.Error())
}
}
如果有錯誤顯示錯誤信息,反之輸出結(jié)果。
創(chuàng)建錯誤對象
內(nèi)置方法
除了內(nèi)置函數(shù)返回錯誤,我們可以創(chuàng)建錯誤,主要有兩種方法:
- errors.New()
- fmt.Errorf()
下面示例展示如何自定義錯誤對象。首先提供一個validate()對象,之后用于檢查用戶數(shù)是否為空,如果為空產(chǎn)生錯誤:
func validate(input string) (bool, error) {
if strings.TrimSpace(input) == "" {
return false, fmt.Errorf("%s can't be empty", input)
//return false, errors.New("cannot be empty")
}
return true, nil
}
func main() {
var name string
fmt.Print("Type your name: \n")
fmt.Scanln(&name)
if valid, err := validate(name); valid {
fmt.Println("hello", name)
} else {
fmt.Println(err.Error())
}
}
第三方庫
有時需要在錯誤對象上增加額外信息:
import "github.com/pkg/errors"
internal := errors.New("internal error")
// 給error增加其他上下文信息
wrapped := errors.Wrap(internal, "wrapper")
// 獲得原始錯誤信息
unwrapped := errors.Cause(wrapped)
pkg/errors是內(nèi)置errors的替代工具,盡管內(nèi)置error也提供了類似功能:
import "errors"
internal := errors.New("internal error")
// add additional context to an error
wrapped := fmt.Errorf("wrapper: %w", internal)
// get original error
unwrapped := errors.Unwrap(wrapped)
但內(nèi)置功能相對較少,建議直接使用pkg/errors.
完整示例:
import (
"fmt"
"github.com/pkg/errors"
"strings"
)
func validate(input string) (bool, error) {
if strings.TrimSpace(input) == "" {
err := errors.New("can't be empty")
return false, errors.Wrap(err, "input error")
}
return true, nil
}
func main() {
var name string
fmt.Print("Type your name: \n")
fmt.Scanln(&name)
if valid, err := validate(name); valid {
fmt.Println("hello", name)
} else {
fmt.Println(errors.Unwrap(err))
}
}
panic
panic是Go內(nèi)置函數(shù),類似其他語言的異常。當(dāng)運行時出現(xiàn)該函數(shù),則程序在該點終止。
聲明panic
go代碼中遇到panic時,不再繼續(xù)執(zhí)行。這種這種場景可以使用內(nèi)置panic函數(shù):
func panic( interface{} )可以傳入字符串或其他類型參數(shù),情況示例:
package main
import "fmt"
func main() {
fmt.Println("start Go program")
panic(" built in panic keyword gives error msg") // panic keyword
fmt.Println("End Go program")
}
內(nèi)置操作
package main
import (
"fmt"
)
func main() {
a,b := 1,0 // variable a & b are declared and initialized
result := a/b // division operation
fmt.Println(result)
}上面代碼因為除數(shù)為0,程序終止并報錯:panic: runtime error: integer divide by zero
另外方法slice時,索引超出范圍時也會panic:
package main
import "fmt"
func main() {
names := []string{ //slice data type
"Learn eTutorials", // index 0
"Golang", //index 1
"panic tutorial", //index 2
}
//fmt.Println(names[0]) commented
//fmt.Println(names[2]) commented
fmt.Println(names[4]) //panic: runtime error: index out of range [4] with length 3
}
那么時間使用panic函數(shù)呢?
- 當(dāng)程序不能繼續(xù)執(zhí)行時使用。舉例,web服務(wù)器不能綁定特定端口。
- 程序出錯時使用。舉例,假設(shè)方法接收指針類型參數(shù),實際調(diào)用時傳入nil。
panic與defer
還是從示例開始吧:
func Name(firstName *string, lastName *string) {
defer fmt.Println("Name function deferred call")
if firstName == nil {
panic("runtime error: first name cannot be nil")
}
if lastName == nil {
panic("runtime error: last name cannot be nil")
}
fmt.Printf("%s %s\n", *firstName, *lastName)
fmt.Println("return from Name")
}
func main() {
defer fmt.Println("main() deffered call")
firstName := "Elon"
Name(&firstName, nil)
fmt.Println("return from main")
}
輸出結(jié)果為:
Name function deferred call
main() deffered call
panic: runtime error: last name cannot be nil
我們看到多個defer,類似棧,先進后出。panic總是讓所有defer執(zhí)行完畢后才拋出。
recover
前面我們看了error和panic兩類異常,前者類似java中的運行時異常,后者類似于非運行時異常。error我們可以捕獲或忽略,但panic要么終止運行,要么手動恢復(fù),也就是手動處理這類錯誤,如給用戶提示。下面同時示例來說明:
func main() {
fmt.Println("lets learn about recover() in golang")
Panicfunc()
fmt.Println("learned all about recover() ")
}
func Panicfunc() {
defer Panicrecover()
fmt.Println("instruction just before panicking situation")
panic("Panicfunc resume execution")
fmt.Println("instruction after panic does not execute")
}
func Panicrecover() {
if err := recover(); err != nil {
fmt.Printf("Recovered from panic: %v \n", err)
}
}
輸出結(jié)果:
lets learn about recover() in golang
instruction just before panicking situation
Recovered from panic: Panicfunc resume execution
learned all about recover()
我們看到panic之后代碼不會執(zhí)行,但recover捕獲的錯誤處理代碼能夠執(zhí)行。
到此這篇關(guān)于Golang中的錯誤處理的示例詳解的文章就介紹到這了,更多相關(guān)Go錯誤處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
windows下使用GoLand生成proto文件的方法步驟
本文主要介紹了windows下使用GoLand生成proto文件的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
Golang實現(xiàn)WebSocket服務(wù)的項目實踐
本文介紹如何使用Golang實現(xiàn)實時后端WebSocket服務(wù),首先使用Gin框架搭建http服務(wù),然后使用gorilla/websocket庫實現(xiàn)簡單后端WebSocket服務(wù),具有一定的參考價值,感興趣的可以了解一下2023-05-05
使用Singleflight實現(xiàn)Golang代碼優(yōu)化
有許多方法可以優(yōu)化代碼以提高效率,減少運行進程就是其中之一,本文我們就來學(xué)習(xí)一下如何通過使用一個Go包Singleflight來減少重復(fù)進程,從而優(yōu)化Go代碼吧2023-09-09
一文帶你了解Go語言中函數(shù)設(shè)計的實踐示例
良好設(shè)計的函數(shù)具有清晰的職責(zé)和邏輯結(jié)構(gòu),提供準(zhǔn)確的命名和適當(dāng)?shù)膮?shù)控制,下面我們將一一描述函數(shù)設(shè)計時能夠遵循的最佳實踐,希望對大家有所幫助2023-06-06
Golang編程并發(fā)工具庫MapReduce使用實踐
這篇文章主要為大家介紹了Golang并發(fā)工具庫MapReduce的使用實踐,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-04-04

