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