mirror of https://github.com/uber-go/multierr.git
Add AppendInto function (#31)
This adds an AppendInto function that behaves similarly to Append
except, it operates on a `*error` on the left side and it reports
whether the right side error was non-nil.
func AppendInto(*error, error) (errored bool)
Making the left side a pointer aligns with the fast path of `Append`.
Returning whether the right error was non-nil aligns with the standard
`if err := ...; err != nil` pattern.
```diff
-if err := thing(); err != nil {
+if multierr.AppendInto(&err, thing()) {
continue
}
```
Resolves #21
This commit is contained in:
parent
c3fc3d02ec
commit
60a318af5f
|
|
@ -1,6 +1,13 @@
|
|||
Releases
|
||||
========
|
||||
|
||||
v1.4.0 (unreleased)
|
||||
===================
|
||||
|
||||
- Add `AppendInto` function to more ergonomically build errors inside a
|
||||
loop.
|
||||
|
||||
|
||||
v1.3.0 (2019-10-29)
|
||||
===================
|
||||
|
||||
|
|
|
|||
52
error.go
52
error.go
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
// Copyright (c) 2019 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -397,3 +397,53 @@ func Append(left error, right error) error {
|
|||
errors := [2]error{left, right}
|
||||
return fromSlice(errors[0:])
|
||||
}
|
||||
|
||||
// AppendInto appends an error into the destination of an error pointer and
|
||||
// returns whether the error being appended was non-nil.
|
||||
//
|
||||
// var err error
|
||||
// multierr.AppendInto(&err, r.Close())
|
||||
// multierr.AppendInto(&err, w.Close())
|
||||
//
|
||||
// The above is equivalent to,
|
||||
//
|
||||
// err := multierr.Append(r.Close(), w.Close())
|
||||
//
|
||||
// As AppendInto reports whether the provided error was non-nil, it may be
|
||||
// used to build a multierr error in a loop more ergonomically. For example:
|
||||
//
|
||||
// var err error
|
||||
// for line := range lines {
|
||||
// var item Item
|
||||
// if multierr.AppendInto(&err, parse(line, &item)) {
|
||||
// continue
|
||||
// }
|
||||
// items = append(items, item)
|
||||
// }
|
||||
//
|
||||
// Compare this with a verison that relies solely on Append:
|
||||
//
|
||||
// var err error
|
||||
// for line := range lines {
|
||||
// var item Item
|
||||
// if parseErr := parse(line, &item); parseErr != nil {
|
||||
// err = multierr.Append(err, parseErr)
|
||||
// continue
|
||||
// }
|
||||
// items = append(items, item)
|
||||
// }
|
||||
func AppendInto(into *error, err error) (errored bool) {
|
||||
if into == nil {
|
||||
// We panic if 'into' is nil. This is not documented above
|
||||
// because suggesting that the pointer must be non-nil may
|
||||
// confuse users into thinking that the error that it points
|
||||
// to must be non-nil.
|
||||
panic("misuse of multierr.AppendInto: into pointer must not be nil")
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
*into = Append(*into, err)
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
// Copyright (c) 2019 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -509,3 +509,74 @@ func TestNilMultierror(t *testing.T) {
|
|||
require.Empty(t, err.Error())
|
||||
require.Empty(t, err.Errors())
|
||||
}
|
||||
|
||||
func TestAppendInto(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
into *error
|
||||
give error
|
||||
want error
|
||||
}{
|
||||
{
|
||||
desc: "append into empty",
|
||||
into: new(error),
|
||||
give: errors.New("foo"),
|
||||
want: errors.New("foo"),
|
||||
},
|
||||
{
|
||||
desc: "append into non-empty, non-multierr",
|
||||
into: errorPtr(errors.New("foo")),
|
||||
give: errors.New("bar"),
|
||||
want: Combine(
|
||||
errors.New("foo"),
|
||||
errors.New("bar"),
|
||||
),
|
||||
},
|
||||
{
|
||||
desc: "append into non-empty multierr",
|
||||
into: errorPtr(Combine(
|
||||
errors.New("foo"),
|
||||
errors.New("bar"),
|
||||
)),
|
||||
give: errors.New("baz"),
|
||||
want: Combine(
|
||||
errors.New("foo"),
|
||||
errors.New("bar"),
|
||||
errors.New("baz"),
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
assert.True(t, AppendInto(tt.into, tt.give))
|
||||
assert.Equal(t, tt.want, *tt.into)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendIntoNil(t *testing.T) {
|
||||
t.Run("nil pointer panics", func(t *testing.T) {
|
||||
assert.Panics(t, func() {
|
||||
AppendInto(nil, errors.New("foo"))
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("nil error is no-op", func(t *testing.T) {
|
||||
t.Run("empty left", func(t *testing.T) {
|
||||
var err error
|
||||
assert.False(t, AppendInto(&err, nil))
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
|
||||
t.Run("non-empty left", func(t *testing.T) {
|
||||
err := errors.New("foo")
|
||||
assert.False(t, AppendInto(&err, nil))
|
||||
assert.Equal(t, errors.New("foo"), err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func errorPtr(err error) *error {
|
||||
return &err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,3 +70,25 @@ func ExampleErrors() {
|
|||
// call 3 failed
|
||||
// call 5 failed
|
||||
}
|
||||
|
||||
func ExampleAppendInto() {
|
||||
var err error
|
||||
|
||||
if multierr.AppendInto(&err, errors.New("foo")) {
|
||||
fmt.Println("call 1 failed")
|
||||
}
|
||||
|
||||
if multierr.AppendInto(&err, nil) {
|
||||
fmt.Println("call 2 failed")
|
||||
}
|
||||
|
||||
if multierr.AppendInto(&err, errors.New("baz")) {
|
||||
fmt.Println("call 3 failed")
|
||||
}
|
||||
|
||||
fmt.Println(err)
|
||||
// Output:
|
||||
// call 1 failed
|
||||
// call 3 failed
|
||||
// foo; baz
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue