Go語言的錯誤處理思想及設計包含以下特征:
* 一個可能造成錯誤的函數,需要返回值中返回一個錯誤接口(error),如果調用是成功的,錯誤接口將返回 nil,否則返回錯誤。
* 在函數調用后需要檢查錯誤,如果發生錯誤,則進行必要的錯誤處理
* ## 錯誤接口的定義格式
error 是 Go 系統聲明的接口類型,代碼如下:
~~~
type error interface {
Error() string
}
~~~
所有符合 Error()string 格式的方法,都能實現錯誤接口,Error() 方法返回錯誤的具體描述,使用者可以通過這個字符串知道發生了什么錯誤。
## 自定義一個錯誤
返回錯誤前,需要定義會產生哪些可能的錯誤,在Go語言中,使用 errors 包進行錯誤的定義,格式如下:
~~~
var err = errors.New("this is an error")
~~~
錯誤字符串由于相對固定,一般在包作用域聲明,應盡量減少在使用時直接使用 errors.New 返回。
#### 1) errors 包
Go語言的 errors 中對 New 的定義非常簡單,代碼如下:
~~~
// 創建錯誤對象
func New(text string) error {
return &errorString{text}
}
// 錯誤字符串
type errorString struct {
s string
}
// 返回發生何種錯誤
func (e *errorString) Error() string {
return e.s
}
~~~
代碼說明如下:
* 第 2 行,將 errorString 結構體實例化,并賦值錯誤描述的成員。
* 第 7 行,聲明 errorString 結構體,擁有一個成員,描述錯誤內容。
* 第 12 行,實現 error 接口的 Error() 方法,該方法返回成員中的錯誤描述。
#### 2) 在代碼中使用錯誤定義
下面的代碼會定義一個除法函數,當除數為 0 時,返回一個預定義的除數為 0 的錯誤。
~~~
package main
import (
"errors"
"fmt"
)
// 定義除數為0的錯誤
var errDivisionByZero = errors.New("division by zero")
func div(dividend, divisor int) (int, error) {
// 判斷除數為0的情況并返回
if divisor == 0 {
return 0, errDivisionByZero
}
// 正常計算,返回空錯誤
return dividend / divisor, nil
}
func main() {
fmt.Println(div(1, 0))
}
~~~
代碼輸出如下:
~~~
0 division by zero
~~~
代碼說明:
* 第 9 行,預定義除數為 0 的錯誤。
* 第 11 行,聲明除法函數,輸入被除數和除數,返回商和錯誤。
* 第 14 行,在除法計算中,如果除數為 0,計算結果為無窮大,為了避免這種情況,對除數進行判斷,并返回商為 0 和除數為 0 的錯誤對象。
* 第 19 行,進行正常的除法計算,沒有發生錯誤時,錯誤對象返回 nil。
## 示例:在解析中使用自定義錯誤
使用 errors.New 定義的錯誤字符串的錯誤類型是無法提供豐富的錯誤信息的,那么,如果需要攜帶錯誤信息返回,就需要借助自定義結構體實現錯誤接口。
下面代碼將實現一個解析錯誤(ParseError),這種錯誤包含兩個內容,分別是文件名和行號,解析錯誤的結構還實現了 error 接口的 Error() 方法,返回錯誤描述時,就需要將文件名和行號返回。
~~~
package main
import (
"fmt"
)
// 聲明一個解析錯誤
type ParseError struct {
Filename string // 文件名
Line int // 行號
}
// 實現error接口,返回錯誤描述
func (e *ParseError) Error() string {
return fmt.Sprintf("%s:%d", e.Filename, e.Line)
}
// 創建一些解析錯誤
func newParseError(filename string, line int) error {
return &ParseError{filename, line}
}
func main() {
var e error
// 創建一個錯誤實例,包含文件名和行號
e = newParseError("main.go", 1)
// 通過error接口查看錯誤描述
fmt.Println(e.Error())
// 根據錯誤接口具體的類型,獲取詳細錯誤信息
switch detail := e.(type) {
case *ParseError: // 這是一個解析錯誤
fmt.Printf("Filename: %s Line: %d\n", detail.Filename, detail.Line)
default: // 其他類型的錯誤
fmt.Println("other error")
}
}
~~~
代碼輸出如下:
~~~
main.go:1
Filename: main.go Line: 1
~~~
代碼說明如下:
* 第 8 行,聲明了一個解析錯誤的結構體,解析錯誤包含有 2 個成員,分別是文件名和行號。
* 第 14 行,實現了錯誤接口,將成員的文件名和行號格式化為字符串返回。
* 第 19 行,根據給定的文件名和行號創建一個錯誤實例。
* 第 25 行,聲明一個錯誤接口類型。
* 第 27 行,創建一個實例,這個錯誤接口內部是 \*ParserError 類型,攜帶有文件名 main.go 和行號 1。
* 第 30 行,調用 Error() 方法,通過第 15 行返回錯誤的詳細信息。
* 第 33 行,通過錯誤斷言,取出發生錯誤的詳細類型。
* 第 34 行,通過分析這個錯誤的類型,得知錯誤類型為 \*ParserError,此時可以獲取到詳細的錯誤信息。
* 第 36 行,如果不是我們能夠處理的錯誤類型,會打印出其他錯誤做出其他的處理。
錯誤對象都要實現 error 接口的 Error() 方法,這樣,所有的錯誤都可以獲得字符串的描述,如果想進一步知道錯誤的詳細信息,可以通過類型斷言,將錯誤對象轉為具體的錯誤類型進行錯誤詳細信息的獲取。
- 1.Go語言前景
- 2.Go語言環境搭建
- 3.Go語言的基本語法
- 3.1變量
- 3.1.1變量聲明
- 3.1.2變量初始化
- 3.1.3多個變量同時賦值
- 3.1.4匿名變量
- 3.1.5變量的作用域
- 3.1.6整型
- 3.1.7浮點類型
- 3.1.8復數
- 3.1.9bool類型
- 3.1.10字符串
- 3.1.11字符類型
- 3.1.12類型轉換
- 3.2常量
- 3.1.1const關鍵字
- 3.2.2模擬枚舉
- 4.Go語言的流程控制
- 4.2循環結構
- 4.3鍵值循環
- 4.4switch語句
- 4.5goto語句
- 4.6break語句
- 4.7continue語句
- 5.Go語言的函數
- 5.1函數聲明
- 5.2函數變量
- 5.3函數類型實現接口
- 5.4閉包
- 5.5可變參數
- 5.6defer(延遲執行語句)
- 5.7處理運行時錯誤
- 5.8宕機(panic)
- 5.9宕機恢復(recover)
- 5.10Test功能測試函數
- 6.Go語言的內置容器
- 6.1數組
- 6.2切片
- 6.3map
- 6.4sync.Map
- 6.5list
- 6.6range
- 7.Go語言的結構體
- 8.Go語言的接口
- 9.Go語言的常用內置包
- 10.Go語言的并發
- 11.Go語言的文件I/O操作
- 12.Go語言的網絡編程
- 13.Go語言的反射
- 14.Go語言的數據庫編程
- 15.Go語言密碼學算法
- 16.Go語言的gin框架
- 17.Go語言的網絡爬蟲
- 18.Go語言的編譯和工具鏈