You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.md 4.6 KiB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. # go-multierror
  2. [![CircleCI](https://img.shields.io/circleci/build/github/hashicorp/go-multierror/master)](https://circleci.com/gh/hashicorp/go-multierror)
  3. [![Go Reference](https://pkg.go.dev/badge/github.com/hashicorp/go-multierror.svg)](https://pkg.go.dev/github.com/hashicorp/go-multierror)
  4. ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/hashicorp/go-multierror)
  5. [circleci]: https://app.circleci.com/pipelines/github/hashicorp/go-multierror
  6. [godocs]: https://pkg.go.dev/github.com/hashicorp/go-multierror
  7. `go-multierror` is a package for Go that provides a mechanism for
  8. representing a list of `error` values as a single `error`.
  9. This allows a function in Go to return an `error` that might actually
  10. be a list of errors. If the caller knows this, they can unwrap the
  11. list and access the errors. If the caller doesn't know, the error
  12. formats to a nice human-readable format.
  13. `go-multierror` is fully compatible with the Go standard library
  14. [errors](https://golang.org/pkg/errors/) package, including the
  15. functions `As`, `Is`, and `Unwrap`. This provides a standardized approach
  16. for introspecting on error values.
  17. ## Installation and Docs
  18. Install using `go get github.com/hashicorp/go-multierror`.
  19. Full documentation is available at
  20. https://pkg.go.dev/github.com/hashicorp/go-multierror
  21. ### Requires go version 1.13 or newer
  22. `go-multierror` requires go version 1.13 or newer. Go 1.13 introduced
  23. [error wrapping](https://golang.org/doc/go1.13#error_wrapping), which
  24. this library takes advantage of.
  25. If you need to use an earlier version of go, you can use the
  26. [v1.0.0](https://github.com/hashicorp/go-multierror/tree/v1.0.0)
  27. tag, which doesn't rely on features in go 1.13.
  28. If you see compile errors that look like the below, it's likely that
  29. you're on an older version of go:
  30. ```
  31. /go/src/github.com/hashicorp/go-multierror/multierror.go:112:9: undefined: errors.As
  32. /go/src/github.com/hashicorp/go-multierror/multierror.go:117:9: undefined: errors.Is
  33. ```
  34. ## Usage
  35. go-multierror is easy to use and purposely built to be unobtrusive in
  36. existing Go applications/libraries that may not be aware of it.
  37. **Building a list of errors**
  38. The `Append` function is used to create a list of errors. This function
  39. behaves a lot like the Go built-in `append` function: it doesn't matter
  40. if the first argument is nil, a `multierror.Error`, or any other `error`,
  41. the function behaves as you would expect.
  42. ```go
  43. var result error
  44. if err := step1(); err != nil {
  45. result = multierror.Append(result, err)
  46. }
  47. if err := step2(); err != nil {
  48. result = multierror.Append(result, err)
  49. }
  50. return result
  51. ```
  52. **Customizing the formatting of the errors**
  53. By specifying a custom `ErrorFormat`, you can customize the format
  54. of the `Error() string` function:
  55. ```go
  56. var result *multierror.Error
  57. // ... accumulate errors here, maybe using Append
  58. if result != nil {
  59. result.ErrorFormat = func([]error) string {
  60. return "errors!"
  61. }
  62. }
  63. ```
  64. **Accessing the list of errors**
  65. `multierror.Error` implements `error` so if the caller doesn't know about
  66. multierror, it will work just fine. But if you're aware a multierror might
  67. be returned, you can use type switches to access the list of errors:
  68. ```go
  69. if err := something(); err != nil {
  70. if merr, ok := err.(*multierror.Error); ok {
  71. // Use merr.Errors
  72. }
  73. }
  74. ```
  75. You can also use the standard [`errors.Unwrap`](https://golang.org/pkg/errors/#Unwrap)
  76. function. This will continue to unwrap into subsequent errors until none exist.
  77. **Extracting an error**
  78. The standard library [`errors.As`](https://golang.org/pkg/errors/#As)
  79. function can be used directly with a multierror to extract a specific error:
  80. ```go
  81. // Assume err is a multierror value
  82. err := somefunc()
  83. // We want to know if "err" has a "RichErrorType" in it and extract it.
  84. var errRich RichErrorType
  85. if errors.As(err, &errRich) {
  86. // It has it, and now errRich is populated.
  87. }
  88. ```
  89. **Checking for an exact error value**
  90. Some errors are returned as exact errors such as the [`ErrNotExist`](https://golang.org/pkg/os/#pkg-variables)
  91. error in the `os` package. You can check if this error is present by using
  92. the standard [`errors.Is`](https://golang.org/pkg/errors/#Is) function.
  93. ```go
  94. // Assume err is a multierror value
  95. err := somefunc()
  96. if errors.Is(err, os.ErrNotExist) {
  97. // err contains os.ErrNotExist
  98. }
  99. ```
  100. **Returning a multierror only if there are errors**
  101. If you build a `multierror.Error`, you can use the `ErrorOrNil` function
  102. to return an `error` implementation only if there are errors to return:
  103. ```go
  104. var result *multierror.Error
  105. // ... accumulate errors here
  106. // Return the `error` only if errors were added to the multierror, otherwise
  107. // return nil since there are no errors.
  108. return result.ErrorOrNil()
  109. ```