github.com/searKing/golang/go@v1.2.74/errors/multi.go (about) 1 // Copyright 2021 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package errors 6 7 import ( 8 "errors" 9 "fmt" 10 "io" 11 ) 12 13 var _ error = multiError{} // verify that Error implements error 14 15 // Multi returns an error with the supplied errors. 16 // If no error contained, return nil. 17 func Multi(errs ...error) error { 18 me := multiError(errs).clean() 19 if me == nil || len(me) == 0 { 20 return nil 21 } 22 return me 23 } 24 25 type multiError []error 26 27 func (e multiError) Error() string { 28 errs := e.clean() 29 if errs == nil || len(errs) == 0 { 30 return "" 31 } 32 message := errs[0].Error() 33 for _, err := range errs[1:] { 34 message += "|" + err.Error() 35 } 36 37 return message 38 } 39 40 func (e multiError) Format(s fmt.State, verb rune) { 41 errs := e.clean() 42 if errs == nil || len(errs) == 0 { 43 return 44 } 45 switch verb { 46 case 'v': 47 if s.Flag('+') { 48 if len(errs) == 1 { 49 _, _ = fmt.Fprintf(s, "%+v", errs[0]) 50 return 51 } 52 _, _ = io.WriteString(s, "Multiple errors occurred:\n") 53 54 _, _ = fmt.Fprintf(s, "|\t%+v", errs[0]) 55 for _, err := range errs[1:] { 56 _, _ = fmt.Fprintf(s, "\n|\t%+v", err) 57 } 58 return 59 } 60 fallthrough 61 case 's', 'q': 62 _, _ = io.WriteString(s, errs.Error()) 63 } 64 } 65 66 // clean removes all none nil elem in all the errors 67 func (e multiError) clean() multiError { 68 var errs []error 69 for _, err := range e { 70 if err != nil { 71 errs = append(errs, err) 72 } 73 } 74 return errs 75 } 76 77 // Is reports whether any error in multiError matches target. 78 func (e multiError) Is(target error) bool { 79 if target == nil { 80 errs := e.clean() 81 if errs == nil || len(errs) == 0 { 82 return true 83 } 84 return false 85 } 86 for _, err := range e { 87 if err == nil { 88 continue 89 } 90 if errors.Is(err, target) { 91 return true 92 } 93 } 94 return false 95 } 96 97 // Unwrap returns the error in e, if there is exactly one. If there is more than one 98 // error, Unwrap returns nil, since there is no way to determine which should be 99 // returned. 100 func (e multiError) Unwrap() error { 101 if len(e) == 1 { 102 return e[0] 103 } 104 // Return nil when e is nil, or has more than one error. 105 // When there are multiple errors, it doesn't make sense to return any of them. 106 return nil 107 } 108 109 // As finds the first error in err's chain that matches target, and if one is found, sets 110 // target to that error value and returns true. Otherwise, it returns false. 111 func (e multiError) As(target any) bool { 112 for _, err := range e { 113 if errors.As(err, target) { 114 return true 115 } 116 } 117 return false 118 }