errors, fmt: add support for wrapping multiple errors · golang/go@4a0a2b3 · GitHub
An error which implements an "Unwrap() []error" method wraps all the non-nil errors in the returned ...
https://github.com/golang/go/commit/4a0a2b33dfa3c99250efa222439f2c27d6780e4a
Go でエラーを扱う際に、複数のエラーを束ねたい事があります。例えば複数のタスクを実行し、1つでもエラーになれば中断するのではなく、一通りタスクを実施し終えた結果を返したい様なニーズです。
package main
import (
"errors"
"log"
"os"
"sync"
)
func doMultiTasks(files []string) error {
var mu sync.Mutex
var wg sync.WaitGroup
var errs []error
for _, file := range files {
wg.Add(1)
go func(file string) {
defer wg.Done()
f, err := os.Open(file)
if err != nil {
mu.Lock()
errs = append(errs, err)
mu.Unlock()
} else {
defer f.Close()
// do something
}
}(file)
}
wg.Wait()
return errors.Join(errs...)
}
func main() {
err := doMultiTasks([]string{"not-found1", "not-found2"})
if err != nil {
if errs, ok := err.(interface{ Unwrap() []error }); ok {
for _, e := range errs.Unwrap() {
log.Println(e)
}
} else {
log.Println(err)
}
}
}
このコードは doMultiTasks に処理対象のファイル名を渡し、一通り実施した結果を返します。エラーを束ねるのに errors.Join
を使います。束ねたエラーは通常踊り error として扱えます。ただし束ねたエラーを戻す関数は現状用意されていませんが、error を複数返す Unwrap という関数で型アサーションしてやる事で複数のエラーに戻せます。
また fmt.Errorf
を使い書式フォーマットに %w
を加える事でメッセージとエラーの両方を埋め込む事が出来ますが、本修正により複数の %w
を埋め込む事ができる様になりました。
package main
import (
"fmt"
"log"
"os"
)
func main() {
err := fmt.Errorf("%w and %w", os.ErrNotExist, os.ErrClosed)
if err != nil {
if errs, ok := err.(interface{ Unwrap() []error }); ok {
for _, e := range errs.Unwrap() {
log.Println(e)
}
} else {
log.Println(err)
}
}
}
個人的にはそれほど多いニーズとは思っていませんが、無くはない程度に感じています。