GO學習筆記——錯誤處理(22)

C++中通過異常機制來處理一些異常的情況,這是C++錯誤處理的方式。

GO語言中,有專門的error類型來表示錯誤,這也是一種內置類型,它一般作爲某些函數返回參數的第二個參數,來判斷函數的調用是否出錯,並可以將出錯原因賦值給error類型的變量。


func main() {
	f,err := os.Open("test.txt")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(f.Name(),"open successfully!")
}

執行結果

open test.txt: The system cannot find the file specified.

當我們試着去打開一個不存在的文件時,該函數其實返回的是兩個值,一個是File類型,一個是error內置類型。

如果函數調用成功,也就是文件打開成功,期間沒有出現任何的錯誤,那麼返回的error就是nil,否則如果出錯,返回的error就不是nil。

所以在這裏也可以看到,error類型的默認零值爲nil。

 

上述代碼中我們將err和nil進行比較,這也是我們一貫的用法。因爲只要函數調用沒有出錯,那麼err的值一定是nil;只要函數調用出錯了,那麼err的值一定是一個不等於nil的值。


error內置類型內部組成

我們先來看一下上述open函數的底層模型

func Open(name string) (*File, error) {
	return OpenFile(name, O_RDONLY, 0)
}

可以看到該函數的第二個返回值是一個error類型,再來看一下這個error類型的底層

type error interface {
	Error() string
}

它其實就是一個接口,這個接口內部實現了一個方法Error,它的返回值是string,所以對於上面的代碼, 我們還可以這麼改。

func main() {
	f,err := os.Open("test.txt")
	if err != nil {
		fmt.Println("Error:",err.Error())
		return
	}
	fmt.Println(f.Name(),"open successfully!")
}

因爲err是一個接口類型,所以我們也可以用接口的方式來調用,執行結果如下

Error: open test.txt: The system cannot find the file specified.

當然我們沒必要這麼麻煩,還是像之前那樣直接打印err就可以了,編譯器會自動幫我們找到err.Error()。



從錯誤獲取更多信息

那麼我們的error類型僅僅只有一個Error方法,我們能獲取的只是出錯原因,這樣我們獲取到的信息就太少了。有時候還想獲取一些別的信息,怎麼辦?

其實open函數源碼中的一行註釋已經告訴我們方法了。

// If there is an error, it will be of type *PathError.

如果有錯誤,那麼它將是類型*PathError。

這個PathError到底是什麼?

// PathError records an error and the operation and file path that caused it.
type PathError struct {
	Op   string
	Path string
	Err  error
}

func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }

這是一個結構體,它實現了Error方法,因此PathError類型實現了error接口。我們也可以直接調用。

通過這個結構體,我們就可以間接地獲取到更多信息。先來看一下之前的出錯原因

 open test.txt: The system cannot find the file specified

對應着上面的PathError類型實現的Error方法,裏面有return語句,我們可以發現,Op類型其實就是open,就是操作方式;Path類型其實是test.txt,就是文件路徑;之後還有一個Err的error類型,打印的是The system cannot find the file specified。

因此,它實現的方式其實就是將三個變量組合起來組合成了一個完整的出錯原因語句。如果我們想要得到完整語句的每一部分,也是可以的。

func main() {
	f,err := os.Open("test.txt")
	if err != nil {
		if pathError,ok := err.(*os.PathError); ok != false {
			fmt.Println(pathError.Op)
			fmt.Println(pathError.Path)
			fmt.Println(pathError.Err.Error())
		}
		return
	}
	fmt.Println(f.Name(),"open successfully!")
}

執行結果

open
test.txt
The system cannot find the file specified.

當然,這僅僅是一個PathError類型表示路徑出錯,還有別的出錯類型,它們也是實現了Error方法,從而實現了error接口,來起到出錯處理的目的,有些類型不僅實現了Error方法,還實現了別的一些方法來獲取別的信息。


自定義錯誤類型

使用New函數可以自定義錯誤類型

func main() {
	err := errors.New("I am an error")
	if err != nil {
		fmt.Println(err)
	}
}

執行結果

I am an error

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章