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)
}
}
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
我們模仿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 起作用囉~
利用自定義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})**即可
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 }