Go error深入

1、Go error本質上是什麼?

type error interface {
	Error() string
}

說白了,error實際上是一個接口,接口裏面就一個方法:Error() string

2、如何自定義錯誤類型

2.1 既然是接口,那就定義一個實現類

package main

import (
	"fmt"
	"reflect"
)

type MyErr1 struct {
}

func (this *MyErr1) Error() string {
	return "this is MyErr1"
}

func main() {
	var err error = nil
	err = &MyErr1{}
	fmt.Println(reflect.TypeOf(err))
	fmt.Println("type err1-->", err)
}

*main.MyErr1
type err1--> this is MyErr1

2.2 也可以藉助fmt,快速創建一個錯誤值

package main

import (
	"fmt"
	"reflect"
)

func main() {
	err := fmt.Errorf("this is MyErr2")
	fmt.Println(reflect.TypeOf(err))
	fmt.Println("type err2-->", err)
}

*errors.errorString
type err2--> this is MyErr2

2.3 還可以藉助errors包

package main

import (
	"errors"
	"fmt"
	"reflect"
)

func main() {
	err := errors.New("this is MyErr3")
	fmt.Println(reflect.TypeOf(err))
	fmt.Println("type err3-->", err)
}

*errors.errorString
type err3--> this is MyErr3

可以看到系統快速創建的error都是*errors.errorString類型的

3、如何判斷錯誤類型

一個方法可能返回多種錯誤類型,調用方常常需要根據不同類型的錯誤做出不同的處理。區分錯誤類型是非常常見和重要的。

我們以*errors.errorString來看看如何區分錯誤類型,常見的做法是這樣子的

package main

import (
	"errors"
	"fmt"
)

var err_1 = errors.New("this is err type 1")
var err_2 = errors.New("this is err type 2")

func main() {
	j, err := tryErr(-10)
	if err == err_1 {
		fmt.Println(err)
		return
	}
	if err == err_2 {
		fmt.Println(err)
		return
	}
	fmt.Println("success", j)
}

func tryErr(i int) (int, error) {
	if i < 0 {
		return -1, err_1
	} else if i == 0 {
		return -1, err_2
	} else {
		return i, nil
	}
}

可以看到這種“常見做法”裏面,錯誤是作爲一個值來判斷的。這種方式與Java裏面的異常機制又很大區別

try{
...
}
catch(Exception1 e1){
...
}
catch(Exception2 e2){
...
}

這個是java裏面的異常機制,可以看到catch是按照類型來匹配的。

這兩種機制孰優孰劣呢?很明顯,以值來判斷錯誤類型只能攜帶錯誤類型本身的類型信息。不能反映出錯誤的更多細節。

4、Go裏面以錯誤值的類型判斷錯誤類型——使用類型斷言

package main

import (
	"fmt"
	"strconv"
)

type MyErr1 struct {
	err_mag string //錯誤消息信息
}

func (this *MyErr1) Error() string {
	return this.err_mag
}

type MyErr2 struct {
	err_mag string //錯誤消息信息
}

func (this *MyErr2) Error() string {
	return this.err_mag
}

func main() {
	j, err := tryErr(-10)
	switch err.(type) {
	case *MyErr1:
		fmt.Println(err)
		return
	case *MyErr2:
		fmt.Println(err)
		return
	default:
		fmt.Println("success", j)
	}
}

func tryErr(i int) (int, error) {
	if i < 0 {
		return -1, &MyErr1{"error message 1-->" + strconv.Itoa(i)}
	} else if i == 0 {
		return -1, &MyErr2{"error message 2-->" + strconv.Itoa(i)}
	} else {
		return i, nil
	}
}

 

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