Go語言基礎-錯誤處理

ffff5發表於2024-10-05

Go 語言錯誤處理機制

錯誤型別

Go 的內建錯誤型別透過 error 介面提供了一種簡單而有效的錯誤處理機制。

error 介面

在 Go 中,error 是一個內建介面,定義如下:

type error interface {
    Error() string
}

error 介面只有一個方法 Error(),返回一個描述錯誤的字串。這使得任何實現了 Error() 方法的型別都可以被視為錯誤。

建立自定義錯誤

開發者可以透過實現 error 介面來自定義錯誤型別。例如:

type MyError struct {
    Message string
    Code    int
}

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

在這個例子中,MyError 是一個自定義錯誤型別,包含錯誤訊息和錯誤程式碼。實現 Error() 方法後,MyError 型別可以作為錯誤使用。

使用內建錯誤型別

Go 標準庫提供了一些內建的錯誤型別,例如:

fmt.Errorf

用於建立帶有格式化字串的錯誤。

err := fmt.Errorf("failed to open file: %s", filename)

errors.New

用於建立一個簡單的錯誤。

err := errors.New("an error occurred")

錯誤包裝

從 Go 1.13 開始,可以使用 fmt.Errorf 來包裝錯誤,以便提供更多上下文資訊。透過 %w 語法,可以將原始錯誤作為新錯誤的一部分:

originalErr := errors.New("original error")
wrappedErr := fmt.Errorf("an additional context: %w", originalErr)

檢查錯誤型別

可以使用 errors.Iserrors.As 來檢查錯誤的型別,方便處理不同型別的錯誤:

if errors.Is(err, specificErr) {
    // 處理特定型別的錯誤
}

返回錯誤

返回錯誤的基本用法如下:

func doSomething() error {
    // 發生錯誤時返回
    return fmt.Errorf("an error occurred")
}

檢查錯誤

檢查返回錯誤的基本示例:

if err := doSomething(); err != nil {
    fmt.Println("Error:", err)
}

panic 與 recover

panic() 是 Go 語言中的一個內建函式,用於觸發恐慌狀態。它主要用於處理程式中不可恢復的錯誤,導致程式停止執行並開始回溯。

panic() 被呼叫時,Go 會執行以下步驟:

  1. 停止當前函式的執行:當前函式會立即停止執行,所有未完成的操作(如 defer 語句)會被執行。
  2. 逐層回溯:程式會逐層回溯,執行每層呼叫棧中的 defer 語句,直到找到一個可以捕獲 panicrecover()
  3. 程式崩潰:如果沒有任何 recover() 捕獲這個 panic,程式將列印錯誤資訊並退出。

recover() 是 Go 語言中用於處理恐慌狀態的內建函式。它的主要作用是捕獲因 panic 觸發的異常,以便程式能夠繼續執行,而不是完全崩潰。

recover() 只能在 defer 宣告的函式中使用。它的功能是捕獲 panic 產生的值,返回該值,如果沒有發生 panic,則返回 nil

示例

package main

import (
    "fmt"
)

func mayPanic() {
    panic("something went wrong!")
}

func safeFunction() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered from panic:", r)
        }
    }()
    
    mayPanic() // 觸發 panic
    fmt.Println("This will not be printed")
}

func main() {
    safeFunction()
    fmt.Println("Program continues after recovery.")
}

輸出結果:

Recovered from panic: something went wrong!
Program continues after recovery.

在上面的示例中,mayPanic 函式觸發了一個 panic,但透過 recover() 捕獲並處理了這個 panic,程式得以繼續執行。

設計模式:返回錯誤 vs使用 panic

  • 返回錯誤:這種模式適合於可以預期的錯誤,如檔案未找到、網路請求失敗等。呼叫者可以透過檢查錯誤值來決定下一步的處理邏輯。

    func readFile(filename string) error {
        // 模擬讀取檔案錯誤
        return fmt.Errorf("file not found: %s", filename)
    }
    
  • 使用 panic:適合處理嚴重的程式錯誤,例如邏輯錯誤、配置錯誤等。這類錯誤通常表明程式碼中存在缺陷,無法繼續執行。

    func main() {
        if err := performCriticalOperation(); err != nil {
            panic(err) // 不可恢復的錯誤
        }
    }
    

相關文章