// 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()