Go 語言的錯誤訊息處理

appleboy發表於2017-03-25

本文轉錄自: Go 語言的錯誤訊息處理

每個語言對於錯誤訊息的處理方式都不同,在學習每個語言時,都要先學會如何在程式內處理錯誤訊息 (Error Handler),而在 Go 語言的錯誤處理是非常簡單,本篇會用簡單的範例教大家 Go 如何處理錯誤訊息。

<!--more-->

Go 輸出錯誤訊息

在 Go 語言內有兩種方式讓函示 (function) 可以回傳錯誤訊息,一種是透過 errors 套件或 fmt 套件,先看看 errors 套件使用方式:

package main

import (
    &quot;errors&quot;
    &quot;fmt&quot;
)

func isEnable(enable bool) (bool, error) {
    if enable {
        return false, errors.New(&quot;You can't enable this setting&quot;)
    }

    return true, nil
}

func main() {
    if _, err := isEnable(true); err != nil {
        fmt.Println(err.Error())
    }
}

請先引入 errors 套件,接著透過 errors.New(&quot;message here&quot;),就可以實現 error 錯誤訊息。接著我們開啟 errors package 原始碼來看看

package errors

// New returns an error that formats as the given text.
func New(text string) error {
    return &amp;errorString{text}
}

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

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

可以發現 errors 套件內提供了 New 函示,讓開發者可以直接建立 error 物件,並且實現了 error interface。在 Go 語言有定義 error interface 為:

type error interface {
    Error() string
}

只要任何 stuct 有實作 Error() 介面,就可以變成 error 物件。這在下面的自訂錯誤訊息會在提到。除了上面使用 errors 套件外,還可以使用 fmt 套件,將上述程式碼改成:

func isEnable(enable bool) (bool, error) {
    if enable {
        return false, fmt.Errorf(&quot;You can't enable this setting&quot;)
    }

    return true, nil
}

這樣也可以成功輸出錯誤訊息,請深入看 fmt.Errorf

// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
func Errorf(format string, a ...interface{}) error {
    return errors.New(Sprintf(format, a...))
}

你可以發現在 fmt 套件內,引用了 errors 套件,所以基本上本質是一樣的。

Go 錯誤訊息測試

在 Go 語言如何測試錯誤訊息,直接引用 testing 套件

package error

import &quot;testing&quot;

func TestIsMyError(t *testing.T) {
    ok, err := isEnable(true)

    if ok {
        t.Fatal(&quot;should be false&quot;)
    }

    if err.Error() != &quot;You can't enable this setting&quot; {
        t.Fatal(&quot;message error&quot;)
    }
}

另外 Go 語言最常用的測試套件 Testify,可以改寫如下:

package error

import (
    &quot;testing&quot;

    &quot;github.com/stretchr/testify/assert&quot;
)

func TestIsEnable(t *testing.T) {
    ok, err := isEnable(true)
    assert.False(t, ok)
    assert.NotNil(t, err)
    assert.Equal(t, &quot;You can't enable this setting&quot;, err.Error())
}

Go 自訂錯誤訊息

從上面的例子可以看到,錯誤訊息都是固定的,如果我們要動態改動錯誤訊息,就必須帶變數進去。底下我們來看看如何實現自訂錯誤訊息:

package main

import (
    &quot;fmt&quot;
)

// MyError is an error implementation that includes a time and message.
type MyError struct {
    Title   string
    Message string
}

func (e MyError) Error() string {
    return fmt.Sprintf(&quot;%v: %v&quot;, e.Title, e.Message)
}

func main() {
    err := MyError{&quot;Error Title 1&quot;, &quot;Error Message 1&quot;}
    fmt.Println(err)

    err = MyError{
        Title:   &quot;Error Title 2&quot;,
        Message: &quot;Error Message 2&quot;,
    }
    fmt.Println(err)
}

也可以把錯誤訊息包成 Package 方式

package error

import (
    &quot;fmt&quot;
)

// MyError is an error implementation that includes a time and message.
type MyError struct {
    Title   string
    Message string
}

func (e MyError) Error() string {
    return fmt.Sprintf(&quot;%v: %v&quot;, e.Title, e.Message)
}

main.go 就可以直接引用 error 套件

package main

import (
    &quot;fmt&quot;

    my &quot;github.com/go-training/training/example04/error&quot;
)

func main() {
    err := my.MyError{&quot;Error Title 1&quot;, &quot;Error Message 1&quot;}
    fmt.Println(err)

    err = my.MyError{
        Title:   &quot;Error Title 2&quot;,
        Message: &quot;Error Message 2&quot;,
    }
    fmt.Println(err)
}

如何測試錯誤訊息是我們自己所定義的呢?請在 error 套件內加入底下測試函示

func IsMyError(err error) bool {
    _, ok := err.(MyError)
    return ok
}

由於我們實作了 error 介面,只要是 Interface 就可以透過 Type assertion 來判斷此錯誤訊息是否為 MyError

package error

import &quot;testing&quot;

func TestIsMyError(t *testing.T) {
    err := MyError{&quot;title&quot;, &quot;message&quot;}

    ok := IsMyError(err)

    if !ok {
        t.Fatal(&quot;error is not MyError&quot;)
    }

    if err.Error() != &quot;title: message&quot; {
        t.Fatal(&quot;message error&quot;)
    }
}

這樣在專案裡就可以實現多個錯誤訊息,寫測試時就可以直接判斷錯誤訊息為哪一種自訂格式。

結論

在 Go 裡面寫錯誤訊息真的很方便又很容易,動態訊息請自定,反之,固定訊息請直接宣告 const 就可以了。在寫套件給大家使用時,大部份都是使用固定訊息,如果是大型專案牽扯到資料庫時,通常會用動態自訂錯誤訊息比較多。

上述程式碼請參考這裡

更多原創文章乾貨分享,請關注公眾號
  • Go 語言的錯誤訊息處理
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章