##9.1 error接口 Go語言引入了一個關於錯誤處理的標準模式,即error接口,它是Go語言內建的接口類型,該接口的定義以下:數組
type error interface {
Error() string
}
複製代碼
Go語言的標準庫代碼包errors爲用戶提供以下方法:bash
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函數:ide
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
}
複製代碼
函數一般在最後的返回值中返回錯誤信息:ui
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) // 使用返回值
}
}
複製代碼
##9.2 panic 在一般狀況下,向程序使用方報告錯誤狀態的方式能夠是返回一個額外的error類型值。spa
可是,當遇到不可恢復的錯誤狀態的時候,如數組訪問越界、空指針引用等,這些運行時錯誤會引發painc異常。這時,上述錯誤處理方式顯然就不適合了。反過來說,在通常狀況下,咱們不該經過調用panic函數來報告普通的錯誤,而應該只把它做爲報告致命錯誤的一種方式。當某些不該該發生的場景發生時,咱們就應該調用panic。線程
通常而言,當panic異常發生時,程序會中斷運行,並當即執行在該goroutine(能夠先理解成線程,在中被延遲的函數(defer 機制)。隨後,程序崩潰並輸出日誌信息。日誌信息包括panic value和函數調用的堆棧跟蹤信息。指針
不是全部的panic異常都來自運行時,直接調用內置的panic函數也會引起panic異常;panic函數接受任何值做爲參數。 func panic(v interface{})日誌
調用panic函數引起的panic異常:code
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()
}
複製代碼
運行結果:
##9.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
}
複製代碼