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
|
Releases
|
||||||
========
|
========
|
||||||
|
|
||||||
|
v1.4.0 (unreleased)
|
||||||
|
===================
|
||||||
|
|
||||||
|
- Add `AppendInto` function to more ergonomically build errors inside a
|
||||||
|
loop.
|
||||||
|
|
||||||
|
|
||||||
v1.3.0 (2019-10-29)
|
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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// 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}
|
errors := [2]error{left, right}
|
||||||
return fromSlice(errors[0:])
|
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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// 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.Error())
|
||||||
require.Empty(t, err.Errors())
|
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 3 failed
|
||||||
// call 5 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