iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 11
0
自我挑戰組

Go to 放棄系列 第 11

go note6 -> 錯誤處理

回傳error type

1.使用fmt.Errorf

package main

import "fmt"

func checkUserNameExist(username string) (bool, error) {
	if username == "foo" {
		return true, fmt.Errorf("username %s already exist", username)
	}

	return false, nil
}
func main() {
	if _, err := checkUserNameExist("foo"); err != nil {
		fmt.Println(err)
	}
}

2.使用errors.New(常用)

package main

import (
	"errors"
	"fmt"
)

func checkUserNameExist(username string) (bool, error) {
	if username == "bar" {
		return true, errors.New(fmt.Sprintf("username %s already exist", username))
	}
	return false, nil
}
func main() {
	if _, err := checkUserNameExist("bar"); err != nil {
		fmt.Println(err)
	}
}

利用vs code 滑鼠移到errors.New的New,按下右鍵預覽定義,可以看到

// Package errors implements functions to manipulate errors.
package errors

// New returns an error that formats as the given text.
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
}

error底層是一個interface,回傳string type,指定一個Error function,回傳一個string,只要用一個error function就可以擁有error型態

所以我們測試只傳字串

package main

import (
	"errors"
	"fmt"
)

func checkUserNameExist(username string) (bool, error) {
	if username == "bar" {
		return true, errors.New("username bar already exist")
	}
	return false, nil
}
func main() {
	if _, err := checkUserNameExist("bar"); err != nil {
		fmt.Println(err)
	}
}

也是可以獲得結果為
// username bar already exist

3.自訂錯誤型態

我們模仿errors.New定義,去自定義~

package main

import (
	"fmt"
)

type errUserNameExist struct {
	UserName string
}

func (e errUserNameExist) Error() string {
	return fmt.Sprintf("username %s already exist", e.UserName)
}

func isErrUserNameExist(err error) bool {
	_, ok := err.(errUserNameExist)
	return ok
}

func checkUserNameExist(username string) (bool, error) {
	if username == "foo" {
		return true, errUserNameExist{UserName: username}
	}
	return false, nil
}
func main() {
	if _, err := checkUserNameExist("foo"); err != nil {
		if isErrUserNameExist(err) {
			fmt.Println(err)
		} else {
			fmt.Println("isErrUserNameExist is false")
		}
	} else {
		fmt.Println("username is ok")
	}
}

再加一個判斷bar字串,使用的判斷error type 不用自定義,使用errors.New
來驗證isErrUserNameExist是否有功效

package main

import (
	"errors"
	"fmt"
)

type errUserNameExist struct {
	UserName string
}

func (e errUserNameExist) Error() string {
	return fmt.Sprintf("username %s already exist", e.UserName)
}

func isErrUserNameExist(err error) bool {
	_, ok := err.(errUserNameExist)
	return ok
}

func checkUserNameExist(username string) (bool, error) {
	if username == "bar" {
		return true, errors.New("bar exist")
	}
	if username == "foo" {
		return true, errUserNameExist{UserName: username}
	}
	return false, nil
}
func main() {
	if _, err := checkUserNameExist("bar"); err != nil {
		if isErrUserNameExist(err) {
			fmt.Println(err)
		} else {
			fmt.Println("bar is exist and isErrUserNameExist is false,because you use error type not custom error type")
		}
	} else {
		fmt.Println("username is ok")
	}
}

結果會顯示bar的確已存在,但你使用的error type非自定義,很明顯isErrUserNameExist functio 起作用囉~
https://ithelp.ithome.com.tw/upload/images/20181026/20112477lKgEJ8FTza.png

結論

利用自定義error type ,可以製作不同的錯誤訊息,例如上面例子的bar is exist and isErrUserNameExist is false,because you use error type not custom error type
可以用在DB錯誤處理訊息
利用error為interface的特性,不管丟struct interger任何型態都可以變為error type
然後要判斷自己的error type是否為自定義(例如上面例子是struct)
就用**err.({驗證的target type})**即可

note

struct 或其他型別都可以實作 error interface 的 Error() function,而上面例子 Error() 的變數被當成 error 型別回傳時,便會自動觸發程式中的 anonymous method

func (e errUserNameExist) Error() string {
	return fmt.Sprintf("username %s already exist", e.UserName)
}

等同他現在身份為errUserNmaeExist.Error() 被觸發

func (e errUserNameExist) Error() string {
	return fmt.Sprintf("username %s already exist", e.UserName)
}
func (e errUserNameExist) Error() string {
	return fmt.Sprintf("usernam!!e %s already exist", e.UserName)
}

會出現錯誤
errUserNameExist.Error redeclared in this block previous declaration at ./main.go:12:6 type errUserNameExist struct { UserName string }


上一篇
go note 5 =>回傳
下一篇
go note 7 -> slice
系列文
Go to 放棄30

尚未有邦友留言

立即登入留言