主頁(yè) > 知識(shí)庫(kù) > Golang try catch與錯(cuò)誤處理的實(shí)現(xiàn)

Golang try catch與錯(cuò)誤處理的實(shí)現(xiàn)

熱門標(biāo)簽:AI電銷 地方門戶網(wǎng)站 百度競(jìng)價(jià)排名 Linux服務(wù)器 呼叫中心市場(chǎng)需求 鐵路電話系統(tǒng) 服務(wù)外包 網(wǎng)站排名優(yōu)化

Golang try catch

雖然在使用Golang的時(shí)候發(fā)現(xiàn)沒有try catch這種錯(cuò)誤處理機(jī)制但是想一想golang作為一門優(yōu)雅的語(yǔ)言,似乎也是情理之中。因?yàn)樵趈ava中 throws在函數(shù)簽名中有一個(gè)關(guān)鍵字,旨在使異常流程比較簡(jiǎn)潔,但是一旦預(yù)期的異常數(shù)量增加,就很難準(zhǔn)確捕捉到具體異常所在。

雖然golang中并不提供try catch的寫法但是零值概念啊等等一些設(shè)計(jì),在加上在panic的時(shí)候還可以使用recover進(jìn)行處理,我覺得還是可以接受的。

在進(jìn)入正題之前我們還是需要新了解一下panic和recover和error

panic

golang新手特別喜歡將panic當(dāng)作exception(我也是這么過來的。。),而這么做會(huì)導(dǎo)致panic被濫用。

panic主要使用場(chǎng)景:

  • 發(fā)生嚴(yán)重錯(cuò)誤必須讓進(jìn)行退出,嚴(yán)重的判斷標(biāo)準(zhǔn)是錯(cuò)誤無法恢復(fù)導(dǎo)致程序無法執(zhí)行或繼續(xù)執(zhí)行或者繼續(xù)執(zhí)行也得不到預(yù)定的結(jié)果,另一些場(chǎng)景就是程序啟動(dòng)需要的初始化數(shù)據(jù)需要在數(shù)據(jù)庫(kù)中讀取,這個(gè)時(shí)候數(shù)據(jù)庫(kù)無法讀取或者不存在配置項(xiàng)不可讀取,這個(gè)時(shí)候哪怕是執(zhí)行下去程序也是毫無意義的,這個(gè)時(shí)候panic暴露出問題反而是更可取的方式。非嚴(yán)重的錯(cuò)誤比如客戶端不合法的請(qǐng)求參數(shù)返回錯(cuò)誤參數(shù)信息提示即可,讓調(diào)用者自己去處理問題,而不是自己panic掛掉。
  • 快速退出錯(cuò)誤處理。也就是下面需要模擬的try catch的行為。大多數(shù)情況下錯(cuò)誤處理都應(yīng)該使用判斷error的機(jī)制,但是有時(shí)函數(shù)調(diào)用棧很深,逐層返回錯(cuò)誤可能需要寫很多冗余代碼,這個(gè)時(shí)候可以使用panic讓程序的控制流直接跳到頂層的recover來進(jìn)行處理。這種場(chǎng)景需要注意必須在包內(nèi)就要recover。讓panic垮包傳遞可能會(huì)導(dǎo)致更復(fù)雜的問題,所以包的到處函數(shù)不應(yīng)該產(chǎn)生panic。

recover

func recover() interface{}

 recover 是一個(gè)內(nèi)建的函數(shù),用于重新獲得 panic 協(xié)程的控制。 只有在延遲函數(shù)的內(nèi)部,調(diào)用 recover 才有用。在延遲函數(shù)內(nèi)調(diào)用 recover,可以取到 panic 的錯(cuò)誤信息,并且停止 panic 續(xù)發(fā)事件(Panicking Sequence),程序運(yùn)行恢復(fù)正常。如果在延遲函數(shù)的外部調(diào)用 recover,就不能停止 panic 續(xù)發(fā)事件。

error

golang中內(nèi)置的錯(cuò)誤類型error是一個(gè)接口,自定義的錯(cuò)誤類型必須實(shí)現(xiàn)error接口,這樣調(diào)用可以通過Error()獲取到具體的錯(cuò)誤信息而不用關(guān)系錯(cuò)誤的具體類型。

// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
 Error() string
}

 很多語(yǔ)言限制函數(shù)只能有一個(gè)返回值,這就顯得尤為寶貴,而golang的多返回值語(yǔ)法糖避免了這種方式帶來的不便,錯(cuò)誤值一般作為返回值列表的最后一個(gè),其他返回值是成功執(zhí)行時(shí)需要返回的信息。也就衍生出了如下判斷:

if err != nil {
    // error handling
} else {
    // normal code
}

雖然這種錯(cuò)誤處理方式代碼寫起來很蛋疼,但是golang風(fēng)格確實(shí)推薦使用此種方式。

預(yù)定義錯(cuò)誤值

var numIsZero = errors.New("num1 is zero")
var numIsNotZero = errors.New("num1 is not zero")
 
func GetInt(num1 int) (int, error) {
 if num1 == 0 {
  return num1, numIsZero
 } else {
  return num1, numIsNotZero
 }
}
 
//比較錯(cuò)誤
func ErrEquals() {
 _, err := GetInt(1)
 if err == numIsNotZero {
   
 }
}

自定義錯(cuò)誤類型

HTTP 表示客戶端的錯(cuò)誤狀態(tài)碼有幾十個(gè)。如果為每種狀態(tài)碼都預(yù)定義相應(yīng)的錯(cuò)誤值,代碼會(huì)變得很繁瑣:

var ErrBadRequest = errors.New("status code 400: bad request")
var ErrUnauthorized = errors.New("status code 401: unauthorized")

這種場(chǎng)景下最佳的最法是自定義一種錯(cuò)誤類型,并且至少實(shí)現(xiàn) Error() 方法(滿足 error 定義):

type HTTPError struct {
    Code        int
    Description string
}
 
func (h *HTTPError) Error() string {
    return fmt.Sprintf("status code %d: %s", h.Code, h.Description)
}

這種方式下進(jìn)行等值判斷時(shí)需要轉(zhuǎn)成具體的自定義類型然后取出 Code 字段判斷:

func request() error {
    return HTTPError{404, "not found"}
}
 
func main() {
    err := request()
 
    if err != nil {
        // an error occured
        if err.(*HTTPError).Code == 404 {
            // handle a "not found" error
        } else {
            // handle a different error
        }
    }
 
}

使用 panic和recover模擬 tyr catch  謹(jǐn)慎!

tyr catch 需要謹(jǐn)慎使用,因?yàn)閜anic / recover 和 try / catch 機(jī)制最大的不同在于控制流程上的區(qū)別。try / catch 機(jī)制控制流作用在 try 代碼塊內(nèi),代碼塊執(zhí)行到異常拋出點(diǎn)(throw)時(shí),控制流跳出 try 代碼塊,轉(zhuǎn)到對(duì)應(yīng)的 catch 代碼塊,然后繼續(xù)往下執(zhí)行。panic / recover 機(jī)制控制流則作用在整個(gè) goroutine 的調(diào)用棧。當(dāng) goroutine 執(zhí)行到 panic 時(shí),控制流開始在當(dāng)前 goroutine 的調(diào)用棧內(nèi)向上回溯(unwind)并執(zhí)行每個(gè)函數(shù)的 defer 。如果 defer 中遇到 recover 則回溯停止,如果執(zhí)行到 goroutine 最頂層的 defer 還沒有 recover ,運(yùn)行時(shí)就輸出調(diào)用棧信息然后退出。所以如果要使用 recover 避免 panic 導(dǎo)致進(jìn)程掛掉,recover 必須要放到 defer 里。為了避免過于復(fù)雜的代碼,最好不要使用嵌套的 defer ,并且 recover 應(yīng)該直接放到 defer 函數(shù)里直接調(diào)用。

package main
 
import (
 "fmt"
)
 
func main() {
 defer func() {
  if err := recover(); err != nil {
   fmt.Println("error:", err)
  }
 }()
 
 fmt.Println("start")
 panic("Big Error")
 fmt.Println("stop")
}

輸出:

start
error: Big Error

此部分的代碼相當(dāng)于try部分的代碼一旦被panic 后面的代碼就不會(huì)被執(zhí)行了,而是跳到 defer部分

       fmt.Println("start")
 panic("Big Error")
 fmt.Println("stop")

 接收到錯(cuò)誤并處理相當(dāng)于catch:

defer func() {
  if err := recover(); err != nil {
   fmt.Println("error:", err)
  }
 }()

注意如果想再次catch需要按照從下往上的循序進(jìn)行異常處理,原因的話了解defer。:

func main() {
 defer func() {
  if err := recover(); err != nil {
   fmt.Println("error:", err)
  }
 }()
 
 defer func() {
  if err := recover(); err != nil {
   fmt.Println("再次panic")
   panic(err)
  }
 }()
 
 fmt.Println("start")
 panic("Big Error")
 fmt.Println("stop")
}
func main() {
 defer func() {
  if err := recover(); err != nil {
   fmt.Println("error:", err)
  }
 }()
 
 defer func() {
  if err := recover(); err != nil {
   fmt.Println("再次panic")
   panic(err)
  }
 }()
 
 defer func() {
  if err := recover(); err != nil {
   fmt.Println("再次panic")
   panic(err)
  }
 }()
 
 defer func() {
  if err := recover(); err != nil {
   fmt.Println("再次panic")
   panic(err)
  }
 }()
 
 fmt.Println("start")
 panic("Big Error")
 fmt.Println("stop")
}

輸出:

start
再次panic
再次panic
再次panic
error: Big Error

到此這篇關(guān)于Golang try catch與錯(cuò)誤處理的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Golang try catch與錯(cuò)誤處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Golang中重復(fù)錯(cuò)誤處理的優(yōu)化方法
  • Golang巧用defer進(jìn)行錯(cuò)誤處理的方法
  • golang 語(yǔ)言中錯(cuò)誤處理機(jī)制

標(biāo)簽:黃山 銅川 仙桃 湖南 崇左 衡水 湘潭 蘭州

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Golang try catch與錯(cuò)誤處理的實(shí)現(xiàn)》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266