日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

一、error是什么?

在C中,返回錯誤通過errno.h中的錯誤代碼來表示,比如0代表No error,也就是沒有錯誤;2代表No such file or directory,也就是找不到指定路徑的文件或文件夾;5代表Input/Output error,表示輸入或輸出出現(xiàn)了錯誤...

而在我們最愛的Golang中,有這樣一個飽受爭議的error類型,它不是一個整數(shù),而是一個接口。

package mAIn

import (
    "errors"
    "fmt"
)

type name struct {
    error string
}

func (n *name) Error() string {
    return fmt.Sprintf("%s : ...", n.error)
}

func main() {
    
    err := judge(11)
    //err := judge(1)
    //err := judge(6)
    fmt.Println(err)
}

func judge(num int) error {
    if num > 5 && num < 10 {
        return errors.New("這個數(shù)字大于5了..")
    }
    if num >= 10 {
        return fmt.Errorf("%d大于或等于10了...", num)
    }
    return &name{error: "hello"}
}

這是三種可以作為error返回值的方式。errors.New()創(chuàng)建出來的error類型其實是errorString結(jié)構(gòu)體。

// src/errors/errors.go

// New returns an error that formats as the given text.
// Each call to New returns a distinct error value even if the text is identical.
func New(text string) error {
 return &errorString{text}
}

// errorString is a trivial implementation of error.
type errorString struct {
 s string
}

func (e *errorString) Error() string {
 return e.s
}

所以我們創(chuàng)建的結(jié)構(gòu)體name其實和errors.New()底層的形式是基本一樣的。

而使用的fmt.Errorf其實是先將字符串格式化然后再調(diào)用errors.New()。

二、error引人爭論的點在哪?

在Go中,設(shè)計者從語言層面要求人們需要明確地處理遇到的錯誤,但是因此導(dǎo)致的問題也十分明顯,使用Go語言編寫的代碼中err會到處都是,不過優(yōu)秀的IDE——Goland能夠解決這個問題,使用Goland能夠?qū)?code>err!=nil這段判斷和處理壓縮,不再干擾代碼的閱讀。

我本人是不太喜歡JAVA的try-catch機制,可能是不太會用,Go語言官方提到try-catch會讓代碼變得比較混亂,很多程序員會胡亂catch異常,導(dǎo)致錯誤處理比較冗長。

而Go語言通過多返回值機制,讓返回錯誤變得很簡單,并且提供panic和error兩種機制,感覺這種機制更有優(yōu)勢,也看起來更簡潔。

煎魚大佬之前有博客談到了Go社區(qū)中關(guān)于Go錯誤處理的新議題,大家想了解的可以看看:

  • Go 錯誤處理新思路?用左側(cè)函數(shù)和表達式:https://juejin.cn/post/7102268049213882398
  • Go try 新提案靠譜嗎?想簡化錯誤處理了 https://juejin.cn/post/7157931922008571940

其實之前Go社區(qū)中出現(xiàn)過多種關(guān)于錯誤處理的新議題,但是都沒有被采納...

三、如何優(yōu)雅的處理錯誤

1. 避免處理“哨兵錯誤”,即Sentinel errors

比如為了判斷err == io.EOF就得引入io包,這是標(biāo)準(zhǔn)庫的包還能接受,如果是第三方庫的包,并且使用“哨兵錯誤”,很容易導(dǎo)致循環(huán)引用的問題。

2. 避免使用error類型

雖然這種錯誤比“哨兵錯誤”要好,它可以捕獲更多關(guān)于錯誤的上下文信息,比如出錯的行數(shù)等其他字段信息。但是又不可避免地在定義錯誤和使用錯誤的包之間形成依賴關(guān)系,又容易導(dǎo)致循環(huán)引用的問題。

3. 使用不透明的“黑盒錯誤”
func f() error{
    sentence,err := say.Hello()
    if err != nil{
        return err
    }
    // ...
}

上面這種寫法是不是我們經(jīng)常會用到?這種情況下,我們只需要判斷err是否為空,不為空,代表有錯誤,就直接返回錯誤,否則就繼續(xù)執(zhí)行后面的流程。

作為程序執(zhí)行者,你沒有能力看到程序錯誤的內(nèi)部信息,只能知道程序有錯或者沒有錯誤。這種錯誤處理作為一種調(diào)試輔助手段還是不錯的。

4. 使用Warp和Cause

第三方庫Github.com/pkg/errors可以輸出錯誤堆棧,并且使用起來很簡單,大家可以了解一下。

// Wrap annotates cause with a message.
func Wrap(cause error, message string) error
// Cause unwraps an annotated error.
func Cause(err error) error

下面來介紹Wrap和Cause的使用樣例:

func ReadFile(path string) ([]byte, error) {
        f, err := os.Open(path)
        if err != nil {
                return nil, errors.Wrap(err, "open failed")
        }
        defer f.Close()

        buf, err := ioutil.ReadAll(f)
        if err != nil {
                return nil, errors.Wrap(err, "read failed")
        }
        return buf, nil
}

func ReadConfig() ([]byte, error) {
        home := os.Getenv("HOME")
        config, err := ReadFile(filepath.Join(home, ".settings.xml"))
        return config, errors.Wrap(err, "could not read config")
}

func main() {
        _, err := ReadConfig()
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
}

如果ReadConfig()執(zhí)行失敗,就會得到下面這一行十分美觀的報錯:

could not read config: open failed: open /Users/dfc/.settings.xml: no such file or directory

而如果用fmt.Printf和%+v格式來輸出就能看到更清晰、更有層次的錯誤堆棧:

func main() {
        _, err := ReadConfig()
        if err != nil {
                fmt.Printf("%+v",err)
                os.Exit(1)
        }
}

聊聊Golang飽受爭議的Error圖片

然后我們再來看Cause的使用。

type temporary interface{
    Temporary() bool
}

// IsTemporary returns true if err is temporary.
func IsTemporary(err error) bool {
        te, ok := errors.Cause(err).(temporary)
        return ok && te.Temporary()
}

當(dāng)需要檢查一個錯誤與一個特定的值或類型時。比如此處,先用Cause取出錯誤,做斷言,最后調(diào)用Temporary(),如果斷言失敗,ok就會是false,就不會調(diào)用右邊的Temporary()去執(zhí)行。

如果 && 運算符左側(cè)的子表達式為 false,則不會檢查右側(cè)的表達式。因為只要有一個子表達式為 false,則整個表達式都為 false,所以再檢查剩余的表達式會浪費 CPU 時間。這被稱為短路評估。

本文轉(zhuǎn)載自微信公眾號「 程序員升級打怪之旅」

分享到:
標(biāo)簽:Golang
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定