1. 程式人生 > >Go基礎程式設計:異常處理(error介面、panic、recover)

Go基礎程式設計:異常處理(error介面、panic、recover)

1 error介面

Go語言引入了一個關於錯誤處理的標準模式,即error介面,它是Go語言內建的介面型別,該介面的定義如下:

type error interface {
    Error() string
}

Go語言的標準庫程式碼包errors為使用者提供如下方法:

package errors

type errorString struct { 
    text string 
}

func New(text string) error { 
    return &errorString{text} 
}

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

另一個可以生成error型別值的方法是呼叫fmt包中的Errorf函式:

package fmt
import "errors"

func Errorf(format string, args ...interface{}) error {
    return errors.New(Sprintf(format, args...))
}

示例程式碼:

import (
    "errors"
    "fmt"
)

func main() {
    var err1 error = errors.New("a normal err1"
) fmt.Println(err1) //a normal err1 var err2 error = fmt.Errorf("%s", "a normal err2") fmt.Println(err2) //a normal err2 }

函式通常在最後的返回值中返回錯誤資訊:

import (
    "errors"
    "fmt"
)

func Divide(a, b float64) (result float64, err error) {
    if b == 0 {
        result = 0.0
        err = errors.New("runtime error: divide by zero"
) return } result = a / b err = nil return } func main() { r, err := Divide(10.0, 0) if err != nil { fmt.Println(err) //錯誤處理 runtime error: divide by zero } else { fmt.Println(r) // 使用返回值 } }

2 panic

在通常情況下,向程式使用方報告錯誤狀態的方式可以是返回一個額外的error型別值。

但是,當遇到不可恢復的錯誤狀態的時候,如陣列訪問越界、空指標引用等,這些執行時錯誤會引起painc異常。這時,上述錯誤處理方式顯然就不適合了。反過來講,在一般情況下,我們不應通過呼叫panic函式來報告普通的錯誤,而應該只把它作為報告致命錯誤的一種方式。當某些不應該發生的場景發生時,我們就應該呼叫panic。

一般而言,當panic異常發生時,程式會中斷執行,並立即執行在該goroutine(可以先理解成執行緒,在中被延遲的函式(defer 機制)。隨後,程式崩潰並輸出日誌資訊。日誌資訊包括panic value和函式呼叫的堆疊跟蹤資訊。

不是所有的panic異常都來自執行時,直接呼叫內建的panic函式也會引發panic異常;panic函式接受任何值作為引數。

func panic(v interface{})

呼叫panic函式引發的panic異常:

func TestA() {
    fmt.Println("func TestA()")
}

func TestB() {
    panic("func TestB(): panic")
}

func TestC() {
    fmt.Println("func TestC()")
}

func main() {
    TestA()
    TestB()//TestB()發生異常,中斷程式
    TestC()
}

執行結果:
這裡寫圖片描述

內建的panic函式引發的panic異常:

func TestA() {
    fmt.Println("func TestA()")
}

func TestB(x int) {
    var a [10]int
    a[x] = 222 //x值為11時,陣列越界
}

func TestC() {
    fmt.Println("func TestC()")
}

func main() {
    TestA()
    TestB(11)//TestB()發生異常,中斷程式
    TestC()
}

執行結果:
這裡寫圖片描述

3 recover

執行時panic異常一旦被引發就會導致程式崩潰。這當然不是我們願意看到的,因為誰也不能保證程式不會發生任何執行時錯誤。

不過,Go語言為我們提供了專用於“攔截”執行時panic的內建函式——recover。它可以是當前的程式從執行時panic的狀態中恢復並重新獲得流程控制權。

    func recover() interface{}

注意:recover只有在defer呼叫的函式中有效。

如果呼叫了內建函式recover,並且定義該defer語句的函式發生了panic異常,recover會使程式從panic中恢復,並返回panic value。導致panic異常的函式不會繼續執行,但能正常返回。在未發生panic時呼叫recover,recover會返回nil。

示例程式碼:

func TestA() {
    fmt.Println("func TestA()")
}

func TestB() (err error) {
    defer func() { //在發生異常時,設定恢復
        if x := recover(); x != nil {
            //panic value被附加到錯誤資訊中;
          //並用err變數接收錯誤資訊,返回給呼叫者。
            err = fmt.Errorf("internal error: %v", x)
        }
    }()

    panic("func TestB(): panic")
}

func TestC() {
    fmt.Println("func TestC()")
}

func main() {
    TestA()
    err := TestB()
    fmt.Println(err)
    TestC()

    /*
        執行結果:
        func TestA()
        internal error: func TestB(): panic
        func TestC()
    */
}

延遲呼叫中引發的錯誤,可被後續延遲呼叫捕獲,但僅最後⼀個錯誤可被捕獲:

func test() {
    defer func() {
        fmt.Println(recover())
    }()

    defer func() {
        panic("defer panic")
    }()

    panic("test panic")
}

func main() {
    test()
    //執行結果:defer panic
}

相關推薦

Go基礎程式設計異常處理(error介面panicrecover)

1 error介面 Go語言引入了一個關於錯誤處理的標準模式,即error介面,它是Go語言內建的介面型別,該介面的定義如下: type error interface { Error() string } Go語言的標準庫程式碼包errors

Go基礎程式設計字串處理

字串在開發中經常用到,包括使用者的輸入,資料庫讀取的資料等,我們經常需要對字串進行分割、連線、轉換等操作,我們可以通過Go標準庫中的strings和strconv兩個包中的函式進行相應的操作。 1 字串操作 下面這些函式來自於strings包,這裡介

Go基礎程式設計JSON處理

JSON (JavaScript Object Notation)是一種比XML更輕量級的資料交換格式,在易於人們閱讀和編寫的同時,也易於程式解析和生成。儘管JSON是JavaScript的一個子集,但JSON採用完全獨立於程式語言的文字格式,且表現為鍵/值對集

go語言基礎語法異常處理,文字檔案處理,JSON處理,檔案操作

一、異常處理 1.err介面的使用 err1 := fmt.Errorf("%s", "this is normal error") fmt.Println("err1=", err1) err2 := errors.New("this is normal error,

十五Go基礎程式設計複合型別—陣列

概述 陣列是指一系列同一型別資料的集合。陣列中包含的每個資料被稱為陣列元素(element),一個數組包含的元素個數被稱為陣列的長度。 陣列⻓度必須是常量,且是型別的組成部分。 [2]int 和 [3]int 是不同型別 var n int = 10 var a [n]i

十四Go基礎程式設計複合型別—指標

指標是一個代表著某個記憶體地址的值。這個記憶體地址往往是在記憶體中儲存的另一個變數的值的起始位置。Go語言對指標的支援介於Java語言和C/C++語言之間,它既沒有想Java語言那樣取消了程式碼對指標的直接操作的能力,也避免了C/C++語言中由於對指標的濫用而造成的安全和可靠性問題。  

十三Go基礎程式設計工程管理

概述 在實際的開發工作中,直接呼叫編譯器進行編譯和連結的場景是少而又少,因為在工程中不  會簡單到只有一個原始碼檔案,且原始檔之間會有相互的依賴關係。如果這樣一個檔案一個檔案逐步編譯,那不亞於一場災難。 Go語言的設計者作為行業老將,自然不會忽略這一點。早期Go語言使用makefile

十二Go基礎程式設計工作區

工作區介紹 Go程式碼必須放在工作區中。工作區其實就是一個對應於特定工程的目錄,它應包含3個子目錄:src目錄、pkg目錄和bin目錄。 src目錄:用於以程式碼包的形式組織並儲存Go原始碼檔案。(比如:.go .c .h .s等) pkg目錄:用於存放經由go install命令構建安裝

十一Go基礎程式設計遞迴函式函式型別匿名函式與閉包

1. 遞迴函式 遞迴指函式可以直接或間接的呼叫自身。 遞迴函式通常有相同的結構:一個跳出條件和一個遞迴體。所謂跳出條件就是根據傳入的引數判斷是否需要停止遞迴,而遞迴體則是函式自身所做的一些處理。 //通過迴圈實現1+2+3……+100 func Test01() int { i

Go基礎程式設計Go語言介紹

Go語言是什麼 2009年11月10日,Go語言正式成為開源程式語言家庭的一員。 Go語言(或稱Golang)是雲端計算時代的C語言。Go語言的誕生是為了讓程式設計師有更高的生產效率,Go語言專門針對多處理器系統應用程式的程式設計進行了優化,使用Go編譯的程式可以媲美C或C++程式碼的速度,

十八Go基礎程式設計複合型別—結構體

1 結構體型別 有時我們需要將不同型別的資料組合成一個有機的整體,如:一個學生有學號/姓名/性別/年齡/地址等屬性。顯然單獨定義以上變數比較繁瑣,資料不便於管理。 結構體是一種聚合的資料型別,它是由一系列具有相同型別或不同型別的資料構成的資料集合。每個資料稱為結構體的

二十Go基礎程式設計正則表示式

正則表示式是一種進行模式匹配和文字操縱的複雜而又強大的工具。雖然正則表示式比純粹的文字匹配效率低,但是它卻更靈活。按照它的語法規則,隨需構造出的匹配模式就能夠從原始文字中篩選出幾乎任何你想要得到的字元組合。 Go語言通過regexp標準包為正則表示式提供了官方支援,如果你已

二十二Go基礎程式設計併發程式設計—goroutine

1 goroutine是什麼 goroutine是Go並行設計的核心。goroutine說到底其實就是協程,但是它比執行緒更小,十幾個goroutine可能體現在底層就是五六個執行緒,Go語言內部幫你實現了這些goroutine之間的記憶體共享。執行goroutine只需極

二十二Go基礎程式設計併發程式設計—channel

goroutine執行在相同的地址空間,因此訪問共享記憶體必須做好同步。goroutine 奉行通過通訊來共享記憶體,而不是共享記憶體來通訊。 引⽤型別 channel 是 CSP 模式的具體實現,用於多個 goroutine 通訊。其內部實現了同步,確保併發安全。

Go基礎程式設計複合型別—陣列

概述 陣列是指一系列同一型別資料的集合。陣列中包含的每個資料被稱為陣列元素(element),一個數組包含的元素個數被稱為陣列的長度。 陣列⻓度必須是常量,且是型別的組成部分。 [2]int 和 [3]int 是不同型別。 var n int

Go基礎程式設計獲取命令列引數

package main import ( "fmt" "os" //os.Args所需的包 ) func main() { args := os.Args //獲取使用者輸入的所有引數 //如果使用者沒有輸入

Go基礎程式設計格式化輸出型別轉換類型別名

使用fmt包來格式化字串 fmt.Printf()格式字串: 列印格式 含義 %% 一個%字面量 %b 一個二進位制整數值(基數為2),或者是一個(高階的)用

Go基礎程式設計HTTP報文淺析

1 概述 1.1 Web工作方式 我們平時瀏覽網頁的時候,會開啟瀏覽器,輸入網址後按下回車鍵,然後就會顯示出你想要瀏覽的內容。在這個看似簡單的使用者行為背後,到底隱藏了些什麼呢? 對於普通的上網過程,系統其實是這樣做的:瀏覽器本身是一個客戶端,當你輸入

Go基礎程式設計HTTP程式設計

Go語言標準庫內建提供了net/http包,涵蓋了HTTP客戶端和服務端的具體實現。使用net/http包,我們可以很方便地編寫HTTP客戶端或服務端的程式。 1 HTTP服務端 示例程式碼:

Go基礎程式設計併發程式設計—channel

goroutine執行在相同的地址空間,因此訪問共享記憶體必須做好同步。goroutine 奉行通過通訊來共享記憶體,而不是共享記憶體來通訊。 引⽤型別 channel 是 CSP 模式的具體實現,用於多個 goroutine 通訊。其內部實現了同步,確保併發