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

Golang利用Recover進行錯誤處理

 更新時間:2023年12月01日 11:01:30   作者:洛天楓  
Golang?中的?recover?是一個鮮為人知但非常有趣和強大的功能,這篇文章小編就來帶大家深入了解一下在Golang中是如何利用Recover進行錯誤處理吧

Golang 中的 recover 是一個鮮為人知但非常有趣和強大的功能。讓我們看看它是如何工作的,以及在 Outreach.io 中如何利用它來處理 Kubernetes 中的錯誤。

Panic/Defer/Recover 基本上是 Golang 中對于其他編程語言中 throw/finally/catch 概念的替代品。它們有一些共同之處,但在一些重要細節(jié)上有所不同。

Defer

要充分理解 recover,我們首先需要談?wù)?nbsp;defer 語句。defer 關(guān)鍵字前置于函數(shù)調(diào)用之前,使得該調(diào)用在當前函數(shù)返回之前執(zhí)行。當我們在一個函數(shù)中使用多個 defer 語句時,它們按照后進先出的順序執(zhí)行,這使得創(chuàng)建清理邏輯變得非常容易,如下例所示:

package main

import (
    "context"
    "database/sql"
    "fmt"
)

func readRecords(ctx context.Context) error {
    db, err := sql.Open("sqlite3", "file:test.db?cache=shared&mode=memory")
    if err != nil {
        return err
    }
    defer db.Close() // 這個函數(shù)調(diào)用將在 readRecords 函數(shù)返回時第三個執(zhí)行

    conn, err := db.Conn(ctx)
    if err != nil {
        return err
    }
    defer conn.Close() // 這個函數(shù)調(diào)用將在第二個執(zhí)行

    rows, err := conn.QueryContext(ctx, "SELECT id FROM users")
    if err != nil {
        return err
    }
    defer rows.Close() // 這個函數(shù)調(diào)用將在第一個執(zhí)行

    for rows.Next() {
        var id int64
        if err := rows.Scan(&id); err != nil {
            return err
        }
        fmt.Println("ID:", id)
    }
    return nil
}

func main() {
    readRecords(context.Background())
}

Panic

我們需要談?wù)摰牡诙€主題是 panic,它是一個導致當前 goroutine 進入 panic 模式的函數(shù)。當前函數(shù)中的正常執(zhí)行流程被停止,僅執(zhí)行 defer 語句,然后對調(diào)用者函數(shù)執(zhí)行相同的操作,因此一直冒泡到堆棧的頂部(main 函數(shù)),然后使程序崩潰。panic 可以直接調(diào)用(傳遞一個值作為參數(shù)),也可以由運行時錯誤引起。例如,由于空指針解引用:

package main

import "fmt"

func main() {
    var x *string
    fmt.Println(*x)
}
// panic: runtime error: invalid memory address or nil pointer dereference

Recover

recover 是一個內(nèi)建函數(shù),它使我們有可能在發(fā)生 panic 時重新獲得控制。它僅在被調(diào)用的延遲函數(shù)中產(chǎn)生效果。在延遲函數(shù)之外調(diào)用時,它總是返回 nil。如果我們處于 panic 模式,調(diào)用 recover 會返回傳遞給 panic 函數(shù)的值?;臼纠?/p>

package main

import "fmt"

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Recovered: %v\\n", r)
        }
    }()

    panic("spam, egg, sausage, and spam")
}
// Recovered: spam, egg, sausage, and spam

我們可以以同樣的方式從運行時錯誤中恢復:

package main

import "fmt"

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Recovered: %v\\n", r)
        }
    }()

    var x *string
    fmt.Println(*x)
}
// Recovered: runtime error: invalid memory address or nil pointer dereference

在這種情況下,recover 返回的值的類型是錯誤(更準確地說是 runtime.errorString)。

有一個限制:我們不能直接從 recover 塊中返回值,因為在 recover 塊中的 return 語句僅從延遲函數(shù)中返回,而不是從周圍的函數(shù)中返回:

package main

import "fmt"

func foo() int {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Recovered: %v\\n", r)
            return 1 // "too many return values" 因為我們僅從匿名函數(shù)返回
        }
    }()

    panic("spam, egg, sausage, and spam")
}

func main() {
    x := foo()
    fmt.Println(x)
}

如果我們想要更改函數(shù)返回的值,我們需要使用命名返回值:

package main

import "fmt"

func foo() (ret int) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("Recovered: %v\\n", r)
            ret = 1
        }
    }()

    panic("spam, egg, sausage, and spam")
}

func main() {
    x := foo()
    fmt.Println("value:", x)
}
// Recovered: spam, egg, sausage, and spam
// value: 1

一個更實際的例子,將 panic 轉(zhuǎn)換為普通錯誤的轉(zhuǎn)換可能如下所示:

package main

import (
    "fmt"

    "github.com/google/uuid"
)

// processInput 嘗試將輸入字符串轉(zhuǎn)換為 uuid.UUID
// 它將 panic 轉(zhuǎn)換為錯誤
func processInput(input string) (u uuid.UUID, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("panic: %v", r)
        }
    }()

    // 一些可能引發(fā) panic 的邏輯(也可以是第三方邏輯),例如:
    u = uuid.MustParse(input)
    return u, nil
}

func main() {
    u, err := processInput("xxx")
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(u)
}
// panic: uuid: Parse(xxx): invalid UUID length: 3
// 00000000-0000-0000-0000-000000000000

現(xiàn)在讓我們嘗試一些稍微

復雜的東西。假設(shè)我們在 Kubernetes 中運行,并且我們想要編寫一個通用的 recover 函數(shù),處理所有未捕獲的 panic 和運行時錯誤,并收集它們的堆棧跟蹤,以便我們可以以結(jié)構(gòu)化的方式記錄它們(例如,以 JSON 格式)。

package main

import (
    "fmt"
    "log"
    "os"

    "github.com/pkg/errors"
)

func foo() string {
    var s *string
    return *s
}

func handlePanic(r interface{}) error {
    var errWithStack error
    if err, ok := r.(error); ok {
        errWithStack = errors.WithStack(err)
    } else {
        errWithStack = errors.Errorf("%+v", r)
    }
    return errWithStack
}

func main() {
    logger := log.New(os.Stdout, "", 0)

    defer func() {
        if r := recover(); r != nil {
            err := handlePanic(r)
            logger.Println(
                "panic occurred",
                "msg", err.Error(),
                "stack", fmt.Sprintf("%+v", err),
            )
        }
    }()

    fmt.Println(foo())
}

// 輸出:
// panic occurred msg: runtime error: invalid memory address or nil pointer dereference
// stack: runtime error: invalid memory address or nil pointer dereference
// main.handlePanic
//        /tmp/sandbox239055659/prog.go:19
// main.main.func1...

recover 函數(shù)并不是 Golang 開發(fā)者的日常必備工具,但正如你所看到的,它在某些情況下非常有用。

到此這篇關(guān)于Golang利用Recover進行錯誤處理的文章就介紹到這了,更多相關(guān)go Recover錯誤處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決panic: assignment to entry in nil map問題

    解決panic: assignment to entry in nil

    這篇文章主要介紹了解決panic: assignment to entry in nil map問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2008-01-01
  • Golang實現(xiàn)不被復制的結(jié)構(gòu)體的方法

    Golang實現(xiàn)不被復制的結(jié)構(gòu)體的方法

    sync包中的許多結(jié)構(gòu)都是不允許拷貝的,因為它們自身存儲了一些狀態(tài)(比如等待者的數(shù)量),如果你嘗試復制這些結(jié)構(gòu)體,就會在你的?IDE中看到警告,那這是怎么實現(xiàn)的呢,下文就來和大家詳細講講
    2023-03-03
  • golang cobra使用chatgpt qdrant實現(xiàn)ai知識庫

    golang cobra使用chatgpt qdrant實現(xiàn)ai知識庫

    這篇文章主要為大家介紹了golang cobra使用chatgpt qdrant實現(xiàn)ai知識庫,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • 淺談Go-zero構(gòu)建RPC與API服務(wù)全流程

    淺談Go-zero構(gòu)建RPC與API服務(wù)全流程

    Go Zero 是一個流行的框架,它提供了構(gòu)建微服務(wù)的基礎(chǔ)設(shè)施,包括 RPC 服務(wù)和 RESTful API,本文主要介紹了Go-zero構(gòu)建RPC與API服務(wù)全流程,感興趣的可以了解一下
    2025-09-09
  • golang打包成帶圖標的exe可執(zhí)行文件

    golang打包成帶圖標的exe可執(zhí)行文件

    這篇文章主要給大家介紹了關(guān)于golang打包成帶圖標的exe可執(zhí)行文件的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2023-06-06
  • Golang 經(jīng)典校驗庫 validator 用法解析

    Golang 經(jīng)典校驗庫 validator 用法解析

    這篇文章主要為大家介紹了Golang 經(jīng)典校驗庫 validator 用法解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • golang并發(fā)編程的實現(xiàn)

    golang并發(fā)編程的實現(xiàn)

    這篇文章主要介紹了golang并發(fā)編程的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-01-01
  • Go 語言 JSON 標準庫的使用

    Go 語言 JSON 標準庫的使用

    今天通過本文給大家介紹Go 語言 JSON 標準庫的使用小結(jié),包括序列化和反序列化的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧
    2021-10-10
  • Go語言的互斥鎖的詳細使用

    Go語言的互斥鎖的詳細使用

    本文主要介紹了Go語言的互斥鎖的詳細使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06
  • 一文教你如何在Golang中用好泛型

    一文教你如何在Golang中用好泛型

    golang的泛型已經(jīng)出來了一年多了,從提案被接受開始我就在關(guān)注泛型了,好用是好用,但問題也很多,所以本文就來教大家如何在Golang中用好泛型吧
    2023-07-07

最新評論

兴隆县| 龙泉市| 原平市| 海口市| 绥宁县| 鄂托克旗| 河间市| 瑞安市| 冷水江市| 枣阳市| 沙坪坝区| 墨竹工卡县| 合水县| 湖南省| 河北区| 敖汉旗| 油尖旺区| 安岳县| 邵阳市| 樟树市| 上栗县| 田东县| 巩留县| 东丽区| 昌邑市| 额济纳旗| 兴业县| 攀枝花市| 秭归县| 社旗县| 昌宁县| 凌云县| 泾源县| 北票市| 丰宁| 吴忠市| 张家界市| 咸阳市| 诸城市| 盐亭县| 香河县|