最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言標(biāo)準(zhǔn)錯誤error全面解析

 更新時間:2024年10月19日 14:32:48   作者:xvwen  
Go語言中的錯誤處理是通過內(nèi)置的error接口來實(shí)現(xiàn)的,其中errorString和wrapError是兩種常見的錯誤類型實(shí)現(xiàn)方式,errorString通過errors.New()方法實(shí)現(xiàn),而wrapError則通過fmt.Errorf()方法實(shí)現(xiàn),支持錯誤的嵌套和解析

錯誤類型

  • errorString

錯誤是程序中處理邏輯和系統(tǒng)穩(wěn)定新的重要組成部分。

在go語言中內(nèi)置錯誤如下:

// 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}

error類型是一個接口類型,內(nèi)含一個Error的方法。它是錯誤的頂級接口,實(shí)現(xiàn)了此內(nèi)置方法的結(jié)構(gòu)體都是其子類。

errorString結(jié)構(gòu)體是內(nèi)置實(shí)現(xiàn)錯誤接口的內(nèi)置實(shí)現(xiàn),源碼如下:

// 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
}

New方法是內(nèi)置錯誤類型實(shí)現(xiàn)。

errors.New()是最常用的錯誤類實(shí)現(xiàn)方法。

  • wrapError

wrapError是error的另一種實(shí)現(xiàn)類,位于fmt的包中,源碼如下:

// Errorf formats according to a format specifier and returns the string as a
// value that satisfies error.
//
// If the format specifier includes a %w verb with an error operand,
// the returned error will implement an Unwrap method returning the operand.
// If there is more than one %w verb, the returned error will implement an
// Unwrap method returning a []error containing all the %w operands in the
// order they appear in the arguments.
// It is invalid to supply the %w verb with an operand that does not implement
// the error interface. The %w verb is otherwise a synonym for %v.
func Errorf(format string, a ...any) error {
	p := newPrinter()
	p.wrapErrs = true
	p.doPrintf(format, a)
	s := string(p.buf)
	var err error
	switch len(p.wrappedErrs) {
	case 0:
		err = errors.New(s)
	case 1:
		w := &wrapError{msg: s}
		w.err, _ = a[p.wrappedErrs[0]].(error)
		err = w
	default:
		if p.reordered {
			slices.Sort(p.wrappedErrs)
		}
		var errs []error
		for i, argNum := range p.wrappedErrs {
			if i > 0 && p.wrappedErrs[i-1] == argNum {
				continue
			}
			if e, ok := a[argNum].(error); ok {
				errs = append(errs, e)
			}
		}
		err = &wrapErrors{s, errs}
	}
	p.free()
	return err
}

type wrapError struct {
	msg string
	err error
}

func (e *wrapError) Error() string {
	return e.msg
}

func (e *wrapError) Unwrap() error {
	return e.err
}

wrapError是另一個內(nèi)置錯誤實(shí)現(xiàn)類,使用%w作為占位符,這里的wrapError實(shí)現(xiàn)了Unwrap方法,用戶返回內(nèi)置的err即嵌套的err。

wrapError還有一個復(fù)數(shù)形式wrapErrors這里不再過多贅述。

  • 自定義錯誤

實(shí)現(xiàn)自定義錯誤非常簡單,面向?qū)ο蟮奶匦詫?shí)現(xiàn)錯誤接口erros就是實(shí)現(xiàn)了錯誤類。安裝go語言的繼承的特性,實(shí)現(xiàn)接口對應(yīng)的方法即可。

type error interface {
	Error() string
}
type MyErr struct {
	e string
}

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


func main(){
	var testErr error
	testErr = &MyErr{"err"}
	fmt.Println(testErr.Error())	
}

上述代碼就是實(shí)現(xiàn)了一個自定義的error類型,注意它是一個結(jié)構(gòu)體,實(shí)際上是errorString的子類。

新建錯誤

上一小節(jié)介紹了三種錯誤類型,前兩中是內(nèi)置的錯誤類型,其中自定義的錯誤是可拓展的,可以實(shí)現(xiàn)前兩種的任意一個。

第一種errorString是實(shí)現(xiàn)比較方便,只有實(shí)現(xiàn)Error()方法;

第二種是wrapError需要實(shí)現(xiàn)兩種方法,還有一種是Unwrap()。

  • errors.New()
err := errors.New("this is a error")
fmt.Printf("----%T----%v\n", err, err)

該方法創(chuàng)建的是errorString類實(shí)例

  • fmt.Errorf()
err = fmt.Errorf("err is: %v", "no found")
fmt.Println(err)

該方法創(chuàng)建的是wrapError類實(shí)例,wrapError也是errorString的子類。

  • 實(shí)例化
type MyErr struct {
	e string
}

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


func main(){
	var testErr error
	testErr = &MyErr{"err"}
	fmt.Println(testErr.Error())
}

由于自定義錯誤一般需要錯誤信息,所以一般直接構(gòu)造方法實(shí)例化。

錯誤解析

  • errors.Is()

errors.Is 用于判斷一個錯誤是否與另一個特定的錯誤相等。它不僅僅是簡單的比較錯誤的值,還會檢查錯誤鏈中的所有錯誤,看看它們是否與給定的目標(biāo)錯誤匹配。

package main

import (
    "errors"
    "fmt"
)

var ErrNotFound = errors.New("not found")

func findItem(id int) error {
    if id == 0 {
        return ErrNotFound
    }
    return nil
}

func main() {
    err := findItem(0)
    if errors.Is(err, ErrNotFound) {
        fmt.Println("Item not found")
    } else {
        fmt.Println("Item found")
    }
}

注意這里有一個坑,就是Is方法判斷的錯誤的類型和錯誤的信息,使用New方法即使構(gòu)建的錯誤信息相同類型不一樣也是不相等的,如下:

err1 := errors.New("err1")
err2 := errors.New("err1")
err := errors.Is(err1, err2)
fmt.Println(err) // 輸出: false
  • errors.As()

errors.As 用于將一個錯誤轉(zhuǎn)換為特定的錯誤類型。如果錯誤鏈中的某個錯誤匹配給定的目標(biāo)類型,那么 errors.As 會將該錯誤轉(zhuǎn)換為該類型,并將其賦值給目標(biāo)變量。

package main

import (
    "errors"
    "fmt"
)

type MyError struct {
    Code int
    Msg  string
}

func (e *MyError) Error() string {
    return fmt.Sprintf("code %d: %s", e.Code, e.Msg)
}

func doSomething() error {
    return &MyError{Code: 404, Msg: "Not Found"}
}

func main() {
    err := doSomething()
    var myErr *MyError
    if errors.As(err, &myErr) {
        fmt.Printf("Custom error: %v (Code: %d)\n", myErr.Msg, myErr.Code)
    } else {
        fmt.Println("Unknown error")
    }
}

可用作類型判斷。

  • errors.Unwrap()

errors.Unwrap() 是一個用于處理嵌套或包裝錯誤的函數(shù)。它的主要作用是提取并返回一個錯誤的直接底層錯誤(即被包裝的錯誤),如果該錯誤沒有被包裝過,則返回 nil

package main

import (
	"errors"
	"fmt"
)

func main() {
	baseErr := errors.New("base error")
	wrappedErr := fmt.Errorf("wrapped error: %w", baseErr)

	// 使用 errors.Unwrap 來提取底層錯誤
	unwrappedErr := errors.Unwrap(wrappedErr)
	fmt.Println("Wrapped error:", wrappedErr)
	fmt.Println("Unwrapped error:", unwrappedErr)
}


// Output
Wrapped error: wrapped error: base error
Unwrapped error: base error

該方法只能獲取錯誤的直接內(nèi)嵌錯誤,如果要獲取更深層次的錯誤需要便利判斷。

注意:

  • errors.Is: 用于判斷一個錯誤是否與特定的錯誤值相等。適合在錯誤鏈中查找某個特定的錯誤(比如一個已知的預(yù)定義錯誤)。
  • errors.As: 用于將錯誤轉(zhuǎn)換為特定的錯誤類型。適合當(dāng)你需要根據(jù)錯誤的具體類型來處理錯誤時使用。
  • errors.Unwrap() 用于從一個包裝錯誤中提取并返回底層的錯誤。如果錯誤沒有被包裝過(或者沒有實(shí)現(xiàn) Unwrap 方法),它會返回 nil。

錯誤處理

if err := findAll(); err != nil {
	// logic
}

這個處理過程是不是很眼熟,利用錯誤解析小節(jié)的處理方法可以對錯誤判斷,進(jìn)行后續(xù)的處理。

go語言也提供了錯誤捕獲recover的機(jī)制和錯誤拋出panic機(jī)制。

  • panic

panic 是 Go 語言中的一種觸發(fā)異常處理機(jī)制的方式。當(dāng)你調(diào)用 panic 時,程序會立刻停止執(zhí)行當(dāng)前函數(shù),并從調(diào)用棧中逐層向上拋出,直到找到一個適合的 recover,或者最終導(dǎo)致程序崩潰。

package main

import "fmt"

func main() {
    fmt.Println("Start")
    panic("Something went wrong!")
    fmt.Println("End") // This line will not be executed
}

當(dāng)程序中調(diào)用了 panic,程序會立刻中止當(dāng)前的控制流,開始回溯幀,并執(zhí)行每一層的 defer 語句。在執(zhí)行完所有的 defer 語句后,如果沒有遇到 recover,程序?qū)⒈罎?,并打?panic 的信息和堆棧跟蹤。

  • recover

recover 是一個內(nèi)建函數(shù),用于恢復(fù) panic。它只能在 defer 函數(shù)中有效。當(dāng) panic 發(fā)生時,如果當(dāng)前函數(shù)任何調(diào)用棧上的函數(shù)中有 defer 函數(shù)調(diào)用了 recover,那么可以捕獲 panic 的內(nèi)容,并使程序恢復(fù)正常執(zhí)行。

package main

import "fmt"

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from:", r)
        }
    }()
    fmt.Println("Start")
    panic("Something went wrong!")
    fmt.Println("End") // This line will not be executed
}

recover 通常用于確保某些代碼塊即使發(fā)生了 panic,也能執(zhí)行資源清理操作,并避免整個程序崩潰。

  • defer

defer 語句用于延遲函數(shù)的執(zhí)行,直到包含 defer 語句的函數(shù)執(zhí)行完畢時,才會執(zhí)行。這通常用于確保資源釋放或清理操作(如關(guān)閉文件、解鎖互斥鎖等)即使在函數(shù)中發(fā)生錯誤或提前返回時也會被執(zhí)行。

  • 執(zhí)行順序: 在一個函數(shù)中,你可以有多個 defer 語句。這些 defer 調(diào)用的執(zhí)行順序是后進(jìn)先出(LIFO)。也就是說,最后一個 defer 聲明的語句會最先執(zhí)行。
  • 捕獲值: defer 語句會在聲明時捕獲它引用的變量的值。也就是說,defer 語句中的參數(shù)會在聲明 defer 時計算,而不是在 defer 執(zhí)行時計算。

三個函數(shù)組合構(gòu)成了錯誤處理,如下:  

package main

import "fmt"

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from panic:", r)
        }
    }()

    fmt.Println("Starting the program")
    causePanic()
    fmt.Println("Program ended gracefully")
}

func causePanic() {
    fmt.Println("About to cause panic")
    panic("A severe error occurred")
    fmt.Println("This line will not execute")
}
Starting the program
About to cause panic
Recovered from panic: A severe error occurred

總結(jié)

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Go語言異常處理案例解析

    Go語言異常處理案例解析

    這篇文章主要介紹了Go語言異常處理案例解析,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • go語言環(huán)境搭建簡述

    go語言環(huán)境搭建簡述

    本文簡單記錄了下go語言環(huán)境的搭建流程,給小伙伴們一個參考,希望大家能夠喜歡。
    2015-01-01
  • golang敏感詞過濾的實(shí)現(xiàn)

    golang敏感詞過濾的實(shí)現(xiàn)

    本文主要介紹了golang敏感詞過濾的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • 詳解Golang中的交叉編譯

    詳解Golang中的交叉編譯

    在 Golang 中,交叉編譯指的是在同一臺機(jī)器上生成針對不同操作系統(tǒng)或硬件架構(gòu)的二進(jìn)制文件,這在開發(fā)跨平臺應(yīng)用或構(gòu)建特定平臺的發(fā)布版本時非常有用,本文就詳細(xì)的給大家介紹一下Golang中的交叉編譯,需要的朋友可以參考下
    2023-08-08
  • Go項目在GoLand中導(dǎo)入依賴標(biāo)紅問題的解決方案

    Go項目在GoLand中導(dǎo)入依賴標(biāo)紅問題的解決方案

    這篇文章主要介紹了Go項目在GoLand中導(dǎo)入依賴標(biāo)紅問題的解決方案,文中通過代碼示例講解的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-06-06
  • Go 數(shù)據(jù)庫查詢與結(jié)構(gòu)體映射的示例詳解

    Go 數(shù)據(jù)庫查詢與結(jié)構(gòu)體映射的示例詳解

    本文主要介紹了如何使用Go語言進(jìn)行數(shù)據(jù)庫查詢并將查詢結(jié)果映射到結(jié)構(gòu)體中,文章詳細(xì)講解了結(jié)構(gòu)體字段導(dǎo)出和db標(biāo)簽的使用方法,并通過示例代碼展示了如何正確地進(jìn)行數(shù)據(jù)庫查詢和結(jié)果映射
    2024-11-11
  • Go REFLECT Library反射類型詳解

    Go REFLECT Library反射類型詳解

    這篇文章主要為大家介紹了Go REFLECT Library反射類型詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Go語言JSON 序列化與反序列化的實(shí)現(xiàn)

    Go語言JSON 序列化與反序列化的實(shí)現(xiàn)

    在Go語言中,通過encoding/json標(biāo)準(zhǔn)庫實(shí)現(xiàn)結(jié)構(gòu)體與JSON之間的相互轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-06-06
  • Go語言使用釘釘機(jī)器人推送消息的實(shí)現(xiàn)示例

    Go語言使用釘釘機(jī)器人推送消息的實(shí)現(xiàn)示例

    本文主要介紹了Go語言使用釘釘機(jī)器人推送消息的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 使用Go語言實(shí)現(xiàn)發(fā)送HTTP請求并給GET添加參數(shù)

    使用Go語言實(shí)現(xiàn)發(fā)送HTTP請求并給GET添加參數(shù)

    在開發(fā)Web應(yīng)用程序時,我們經(jīng)常需要向服務(wù)器發(fā)送HTTP請求,本文將介紹一下使用Go語言發(fā)送HTTP請求,并給GET請求添加參數(shù)的方法,感興趣的小伙伴可以了解一下
    2023-07-07

最新評論

潼南县| 泰来县| 滨州市| 宝坻区| 怀集县| 马公市| 宁明县| 沾化县| 华亭县| 达孜县| 金溪县| 交城县| 蒙山县| 荥阳市| 延边| 璧山县| 综艺| 景洪市| 杭州市| 临泽县| 巴彦淖尔市| 神农架林区| 浦东新区| 阳原县| 茂名市| 新平| 甘南县| 杭锦后旗| 翁源县| 德昌县| 福鼎市| 青铜峡市| 清徐县| 遵化市| 班玛县| 军事| 河东区| 集安市| 甘肃省| 巴南区| 镇江市|