【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()
相关文章
相关标签/搜索