1. 程式人生 > 其它 >Go語言學習[10]_異常處理

Go語言學習[10]_異常處理

技術標籤:GOgo

Go語言學習

道法自然

文章目錄


前言

Go(又稱Golang)是Google開發的一種靜態強型別、編譯型、併發型,並具有垃圾回收功能的程式語言。Go語言語法簡單,包含了類C語法。快速的編譯時間,開發效率和執行效率高。組合的思想、無侵入式的介面。


參考連結

一、異常處理

1.1 error

Go語言內建了一個簡單的錯誤介面作為一種錯誤處理機制,介面定義如下:

type error interface {
	Error() string
}

它包含一個 Error() 方法,返回值為string

Go的error構造有兩種方式,分別是
第一種:errors.New()

err := errors.New("This is an error")
if err != nil {
  fmt.Print(err)
}

第二種:fmt.Errorf()

err := fmt.Errorf("This is an error")
if err != nil {
  fmt.Print(err)
}

除了直接使用Go自帶的方法,還可以自定義錯誤。下面以自然數函式作為例子:

type NotNature float64

func (err NotNature)
Error() string { return fmt.Sprintf("自然數為大於或等於0的數: %v", float64(err)) } func Nature(x float64) (float64,error) { if x<0 { return 0,NotNature(x) } else { return x,nil } } func main() { fmt.Println(Nature(1)) fmt.Println(Nature(-1)) }

需要注意一下幾點:

1.如果函式需要處理異常,通常將error作為多值返回的最後一個值,返回的error值為nil則表示無異常,非nil則是有異常。

2.一般先用if語句處理error!=nil,正常邏輯放if後面。

Go語言的error代表的並不是真“異常”,只是通過返回error來表示錯誤資訊,換句話說,不是執行時錯誤範圍預定義的錯誤,某種不符合期望的行為並不會導致程式無法執行(自然數函式例子),都應使用error進行異常處理。當程式出現重大錯誤,如陣列越界,才會將其當成真正的異常,並用panic來處理。

1.2 panic

Go不使用try…catch方法來處理異常,而是使用panic和recover

先上程式碼舉一個簡單的例子

func main() {
  fmt.Println("Hello,Go!")
  panic(errors.New(" i am a error"))
  fmt.Println("hello,again!")
}

輸出:

Hello,Go!
panic:  i am a error

goroutine 1 [running]:
main.main()
	~/error.go:12 +0xb5
exit status 2

可以看到,panic後面的程式不會被執行了。但是我們捕捉異常並不是為了停止程式(一般情況),而是為了讓程式能正常執行下去,這時候就到recover出場了。
可以看到,panic後面的程式不會被執行了。但是我們捕捉異常並不是為了停止程式(一般情況),而是為了讓程式能正常執行下去,這時候就到recover出場了。

package main

import "fmt"

func main(){
  defer func(){
    fmt.Println("我是defer裡面第一個列印函式")
    if err:=recover();err!=nil{
        fmt.Println(err)
    }
    fmt.Println("我是defer裡面第二個列印函式")
  }()
  f()
}

func f(){
  fmt.Println("1")
  panic("我是panic")
  fmt.Println("2")
}

輸出:

1
我是defer裡面第一個列印函式
我是panic
我是defer裡面第二個列印函式

可以看到,f函式一開始正常列印,當遇到panic,就跳到defer函式,執行defer函式裡的內容

需要注意的是,defer函式裡列印的err其實就是panic裡面的內容。

下面詳細介紹一下panic和recover的原理。首先來看一下panic和recover的官方定義

func panic(v interface{})

內建函式panic會停止當前goroutine的正常執行。當函式F呼叫panic時,F的正常執行立即停止。任何被F延遲執行的函式都將以正常的方式執行,然後F返回其呼叫者。對呼叫方G來說,對F的呼叫就像呼叫panic一樣,終止G的執行並執行任何延遲的函式。直到執行goroutine中的所有函式都按逆序停止。此時,程式將以非0退出程式碼終止。此終止序列稱為panicking,可由內建函式recover控制。

func recover() interface{}

recover內建函式允許程式管理panicking的goroutine的行為。在defer函式(但不是它呼叫的任何函式)內執行恢復呼叫,通過恢復正常執行來停止panicking序列,並檢索傳遞給panic呼叫的錯誤值。如果在defer函式之外呼叫recover,則不會停止panicking的序列。在這種情況下,或者當goroutine不panicking時,或者提供給panic的引數是nil,recover返回nil。因此,recover的返回值報告goroutine是否panicking
ps:defer和recover必須在panic之前定義,否則無效。

1.3 原始碼分析

errors.New的定義如下

// src/errors/errors.go

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

1.New函式返回格式為給定文字的錯誤

2.即使文字是相同的,每次對New的呼叫都會返回一個不同的錯誤值。


總結