内射老阿姨1区2区3区4区_久久精品人人做人人爽电影蜜月_久久国产精品亚洲77777_99精品又大又爽又粗少妇毛片

Golang中怎么對錯誤進(jìn)行處理

這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)Golang中怎么對錯誤進(jìn)行處理,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

企業(yè)建站必須是能夠以充分展現(xiàn)企業(yè)形象為主要目的,是企業(yè)文化與產(chǎn)品對外擴展宣傳的重要窗口,一個合格的網(wǎng)站不僅僅能為公司帶來巨大的互聯(lián)網(wǎng)上的收集和信息發(fā)布平臺,創(chuàng)新互聯(lián)公司面向各種領(lǐng)域:玻璃鋼坐凳網(wǎng)站設(shè)計成都全網(wǎng)營銷推廣解決方案、網(wǎng)站設(shè)計等建站排名服務(wù)。


首先介紹幾種常見的創(chuàng)建錯誤的方法

基于字符串的錯誤

err1 := errors.New("math: square root of negative number") err2 := fmt.Errorf("math: square root of negative number %g", x)

帶有數(shù)據(jù)的自定義錯誤

package serr  import (   "fmt"   "github.com/satori/go.uuid"   "log"   "runtime/debug"   "time" ) // 自定義基礎(chǔ)錯誤類型 type BaseError struct {   InnerError error   Message    string   StackTrace string   Misc       map[string]interface{} }  func WrapError(err error, message string, messageArgs ...interface{}) BaseError {   return BaseError{     InnerError: err,     Message:    fmt.Sprintf(message, messageArgs),     StackTrace: string(debug.Stack()),     Misc:       make(map[string]interface{}),   } }  func (err *BaseError) Error() string { // 實現(xiàn) Error 接口   return err.Message }  // 具體使用 // "intermediate" module type IntermediateErr struct {   error }  func runJob(id string) error {   const jobBinPath = "/bad/job/binary"   isExecutable, err := isGloballyExec(jobBinPath)   iferr != nil{     return IntermediateErr{wrapError( err,     "cannot run job %q: requisite binaries not available",     id, )}   } else if isExecutable == false {     return wrapError(       nil,       "cannot run job %q: requisite binaries are not executable", id,     )   }   return exec.Command(jobBinPath, "--id="+id).Run() }

拋出問題

開發(fā)中經(jīng)常需要檢查返回的錯誤值并作相應(yīng)處理。下面給出一個最簡單的示例。

import (    "database/sql"    "fmt" )  func GetSql() error {    return sql.ErrNoRows }  func Call() error {    return GetSql() }  func main() {    err := Call()    if err != nil {       fmt.Printf("got err, %+v\n", err)    } } //Outputs: // got err, sql: no rows in result set

有時需要根據(jù)返回的 error 類型作不同處理,例如:

import (    "database/sql"    "fmt" )  func GetSql() error {    return sql.ErrNoRows }  func Call() error {    return GetSql() }  func main() {    err := Call()    if err == sql.ErrNoRows {       fmt.Printf("data not found, %+v\n", err)       return    }    if err != nil {       // Unknown error    } } //Outputs: // data not found, sql: no rows in result set

實踐中經(jīng)常需要為錯誤增加上下文信息后再返回,以方便調(diào)用者了解錯誤場景。例如 Getcall 方法時常寫成:

func Getcall() error {    return fmt.Errorf("GetSql err, %v", sql.ErrNoRows) }

不過這個時候 err==sql.ErrNoRows  就不成立了。除此之外,上述寫法都在返回錯誤時都丟掉了調(diào)用棧這個重要的信息。我們需要更靈活、更通用的方式來應(yīng)對此類問題。

解決方案

針對存在的不足,目前有幾種解決方案。這些方式可以對錯誤進(jìn)行上下文包裝,并攜帶原始錯誤信息, 還能盡量保留完整的調(diào)用棧

方案 1:github.com/pkg/errors

如果只有錯誤的文本,我們很難定位到具體的出錯地點。雖然通過在代碼中搜索錯誤文本也是有可能找到出錯地點的,但是信息有限。所以,在實踐中,我們往往會將出錯時的調(diào)用棧信息也附加上去。調(diào)用棧對消費方是沒有意義的,從隔離和自治的角度來看,消費方唯一需要關(guān)心的就是錯誤文本和錯誤類型。調(diào)用棧對實現(xiàn)者自身才是是有價值的。所以,如果一個方法需要返回錯誤,我們一般會使用  errors.WithStack(err) 或者 errors.Wrap(err,"custom message")  的方式,把此刻的調(diào)用棧加到error里去,并且在某個統(tǒng)一地方記錄日志,方便開發(fā)者快速定位問題。

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. Wrap 方法用來包裝底層錯誤,增加上下文文本信息并附加調(diào)用棧。一般用于包裝對第三方代碼(標(biāo)準(zhǔn)庫或第三方庫)的調(diào)用。

  3. WithMessage 方法僅增加上下文文本信息,不附加調(diào)用棧。如果確定錯誤已被 Wrap 過或不關(guān)心調(diào)用棧,可以使用此方法。注意:不要反復(fù) Wrap  ,會導(dǎo)致調(diào)用棧重復(fù)

  4. Cause 方法用來判斷底層錯誤 。

現(xiàn)在我們用這三個方法來重寫上面的代碼:

import (    "database/sql"    "fmt"     "github.com/pkg/errors" )  func GetSql() error {    return errors.Wrap(sql.ErrNoRows, "GetSql failed") }  func Call() error {    return errors.WithMessage(GetSql(), "bar failed") }  func main() {    err := Call()    if errors.Cause(err) == sql.ErrNoRows {       fmt.Printf("data not found, %v\n", err)       fmt.Printf("%+v\n", err)       return    }    if err != nil {       // unknown error    } } /*Output: data not found, Call failed: GetSql failed: sql: no rows in result set sql: no rows in result set main.GetSql     /usr/three/main.go:11 main.Call     /usr/three/main.go:15 main.main     /usr/three/main.go:19 runtime.main     ... */

從輸出內(nèi)容可以看到, 使用 %v 作為格式化參數(shù),那么錯誤信息會保持一行, 其中依次包含調(diào)用棧的上下文文本。使用 %+v  ,則會輸出完整的調(diào)用棧詳情。如果不需要增加額外上下文信息,僅附加調(diào)用棧后返回,可以使用 WithStack 方法:

func GetSql() error {    return errors.WithStack(sql.ErrNoRows) }

注意:無論是 Wrap , WithMessage 還是 WithStack ,當(dāng)傳入的 err 參數(shù)為 nil 時, 都會返回nil,  這意味著我們在調(diào)用此方法之前無需作 nil 判斷,保持了代碼簡潔

方案 2:golang.org/x/xerrors

結(jié)合社區(qū)反饋,Go 團隊開始考慮在 Go 2 中簡化錯誤處理的提案。Go 核心團隊成員 Russ Cox 在xerrors中部分實現(xiàn)了提案中的內(nèi)容。它用與  github.com/pkg/errors 相似的思路解決同一問題, 引入了一個新的 fmt 格式化動詞: %w,使用 Is 進(jìn)行判斷。

import (    "database/sql"    "fmt"     "golang.org/x/xerrors" )  func Call() error {    if err := GetSql(); err != nil {       return xerrors.Errorf("bar failed: %w", GetSql())    }    return nil }  func GetSql() error {    return xerrors.Errorf("GetSql failed: %w", sql.ErrNoRows) }  func main() {    err := Call()    if xerrors.Is(err, sql.ErrNoRows) {       fmt.Printf("data not found, %v\n", err)       fmt.Printf("%+v\n", err)       return    }    if err != nil {       // unknown error    } } /* Outputs: data not found, Call failed: GetSql failed: sql: no rows in result set bar failed:     main.Call         /usr/four/main.go:12   - GetSql failed:     main.GetSql         /usr/four/main.go:18   - sql: no rows in result set */

與 github.com/pkg/errors 相比,它有幾點不足:

  • 使用 : %w 代替了 Wrap , 看似簡化, 但失去了編譯期檢查。如果沒有冒號,或 : %w  不位于于格式化字符串的結(jié)尾,或冒號與百分號之間沒有空格,包裝將失效且不報錯;

  • 而且,調(diào)用 xerrors.Errorf 之前需要對參數(shù)進(jìn)行nil判斷。這完全沒有簡化開發(fā)者的工作

方案 3:Go 1.13 內(nèi)置支持

Go 1.13 將 xerrors 的部分功能(不是全部)整合進(jìn)了標(biāo)準(zhǔn)庫。它繼承了上面提到的 xerrors 的全部缺點,  并額外貢獻(xiàn)了一項。因此目前沒有使用它的必要。

import (    "database/sql"    "errors"    "fmt" )  func Call() error {    if err := GetSql(); err != nil {       return fmt.Errorf("Call failed: %w", GetSql())    }    return nil }  func GetSql() error {    return fmt.Errorf("GetSql failed: %w", sql.ErrNoRows) }  func main() {    err := Call()    if errors.Is(err, sql.ErrNoRows) {       fmt.Printf("data not found,  %+v\n", err)       return    }    if err != nil {       // unknown error    } } /* Outputs: data not found,  Call failed: GetSql failed: sql: no rows in result set */

上面的代碼與 xerrors 版本非常接近。但是它不支持調(diào)用棧信息輸出, 根據(jù)官方的說法, 此功能沒有明確的支持時間。因此其實用性遠(yuǎn)低于  github.com/pkg/errors。

Golang 中將來可能的錯誤處理方式

在 Go2 的草案中,我們看到了有關(guān)于 error 相關(guān)的一些提案,那就是 check/handle 函數(shù)。

我們也許在下一個大版本的 Golang 可以像下面這樣處理錯誤:

import "fmt" func game() error {     handle err {         return fmt.Errorf("dependencies error: %v", err)     }      resource := check findResource() // return resource, error     defer func() {         resource.Release()     }()      profile := check loadProfile() // return profile, error     defer func() {         profile.Close()     }      // ... }

感興趣的同學(xué)可以關(guān)注下這個提案:https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md

得出結(jié)論

  • 重要的是要記住,包裝錯誤會使該錯誤成為 API 的一部分。如果您不想將來將錯誤作為 API  的一部分來支持,則不應(yīng)包裝該錯誤。無論是否包裝錯誤,錯誤文本都將相同。那些試圖理解錯誤的人將得到相同的信息,無論采用哪種方式;  是否要包裝錯誤的選擇取決于是否要給程序提供更多信息,以便他們可以做出更明智的決策,還是保留該信息以保留抽象層。

通過以上對比, 相信你已經(jīng)有了選擇。再明確一下我的看法,如果你正在使用 github.com/pkg/errors  ,那就保持現(xiàn)狀吧。目前還沒有比它更好的選擇。如果你已經(jīng)大量使用 golang.org/x/xerrors , 別盲目換成 go 1.13 的內(nèi)置方案。

總的來說,Go 在誕生之初就在各個方面表現(xiàn)得相當(dāng)成熟、穩(wěn)健。在演進(jìn)路線上很少出現(xiàn)猶疑和搖擺, 而在錯誤處理方面卻是個例外。除了被廣泛吐槽的 if err  != nil 之外, 就連其改進(jìn)路線也備受爭議、分歧明顯,以致于一個改進(jìn)提案都會因為壓倒性的反對意見而不得不作出調(diào)整。好在 Go  團隊比以前更加樂于傾聽社區(qū)意見,團隊甚至專門就此問題建了個反饋收集頁面。

上述就是小編為大家分享的Golang中怎么對錯誤進(jìn)行處理了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

新聞名稱:Golang中怎么對錯誤進(jìn)行處理
網(wǎng)站URL:http://www.rwnh.cn/article20/jdiijo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)、營銷型網(wǎng)站建設(shè)、品牌網(wǎng)站建設(shè)、定制開發(fā)、域名注冊、網(wǎng)站營銷

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

微信小程序開發(fā)
万宁市| 华池县| 澜沧| 锦州市| 衢州市| 鹤峰县| 天长市| 周口市| 天气| 龙海市| 监利县| 竹山县| 林周县| 泉州市| 林周县| 屏南县| 昔阳县| 正宁县| 遂平县| 轮台县| 双鸭山市| 嵊州市| 寿阳县| 行唐县| 枝江市| 密云县| 元阳县| 河南省| 澄江县| 河曲县| 南安市| 郴州市| 秦皇岛市| 北碚区| 江口县| 卓资县| 巴南区| 凯里市| 井冈山市| 镇平县| 宝鸡市|