【Golang源碼閱讀】errors/wrap.go

// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package errors

import (
	"internal/reflectlite"
)

// Unwrap 返回對 err 調用 Unwrap 方法的結果,若是 err 的類型包含返回錯誤的 Unwrap 方法。不然,Unwrap 返回 nil。
func Unwrap(err error) error {
	u, ok := err.(interface {
		Unwrap() error
	})
	if !ok {
		return nil
	}
	return u.Unwrap()
}

// Is 報告 err 鏈中的任何錯誤是否與目標匹配。
//
// 該鏈由 err 自己和經過重複調用 Unwrap 得到的錯誤序列組成。
//
// 若是錯誤等於該目標,或者若是它實現了 Is(error) bool 方法使得 Is(target) 返回 true,則認爲錯誤與該目標匹配。
//
// 錯誤類型可能提供 Is 方法,所以能夠將其視爲等同於現有錯誤。 例如,若是 MyError 定義了
//
//	func (m MyError) Is(target error) bool { return target == fs.ErrExist }
//
// 而後 Is(MyError{}, fs.ErrExist) 返回 true。 有關標準庫中的示例,請參見 syscall.Errno.Is。
func Is(err, target error) bool {
	if target == nil {
		return err == target
	}

	isComparable := reflectlite.TypeOf(target).Comparable()
	for {
		if isComparable && err == target {
			return true
		}
		if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
			return true
		}
		// TODO: 考慮支持 target.Is(err)。 這將容許用戶定義謂詞,但也可能容許處理草率的 API,從而更容易擺脫它們。
		if err = Unwrap(err); err == nil {
			return false
		}
	}
}

// As 查找與目標匹配的 err 鏈中的第一個錯誤,若是是,則將目標設置爲該錯誤值並返回 true。 不然,它返回 false。
//
// 該鏈由 err 自己和經過重複調用 Unwrap 得到的錯誤序列組成。
//
// 若是錯誤的具體值可分配給目標指向的值,或者錯誤具備方法 As(interface{}) bool 使得 As(target) 返回 true,則錯誤與目標匹配。
// 在後一種狀況下,As 方法負責設置目標。
//
// 錯誤類型可能提供 As 方法,所以能夠將其視爲不一樣的錯誤類型。
//
// 若是目標不是指向實現錯誤的類型或任何接口類型的非空指針,則做爲panics。
func As(err error, target interface{}) bool {
	if target == nil {
		panic("errors: target cannot be nil")
	}
	val := reflectlite.ValueOf(target)
	typ := val.Type()
	if typ.Kind() != reflectlite.Ptr || val.IsNil() {
		panic("errors: target must be a non-nil pointer")
	}
	if e := typ.Elem(); e.Kind() != reflectlite.Interface && !e.Implements(errorType) {
		panic("errors: *target must be interface or implement error")
	}
	targetType := typ.Elem()
	for err != nil {
		if reflectlite.TypeOf(err).AssignableTo(targetType) {
			val.Elem().Set(reflectlite.ValueOf(err))
			return true
		}
		if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
			return true
		}
		err = Unwrap(err)
	}
	return false
}

var errorType = reflectlite.TypeOf((*error)(nil)).Elem()
相關文章
相關標籤/搜索