Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Goのmultiple errorsについて (2024年4月版)
Search
syumai
April 23, 2024
Programming
14k
5
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Goのmultiple errorsについて (2024年4月版)
syumai
April 23, 2024
More Decks by syumai
See All by syumai
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.8k
Oxlintのカスタムルールの現況
syumai
6
1.3k
Oxlintはいかにしてtsgolintのlint ruleを呼び出しているのか
syumai
2
1.4k
『[入門] Cloudflare Workers』本はなぜ誕生したのか
syumai
0
490
tsgolintはいかにしてtypescript-goの非公開APIを呼び出しているのか
syumai
9
3.2k
知られているようで知られていない JavaScriptの仕様 4選
syumai
3
1.3k
CloudflareのSandbox SDKを試してみた
syumai
0
970
実践AIチャットボットUI実装入門
syumai
9
4.3k
ProxyによるWindow間RPC機構の構築
syumai
3
1.5k
Other Decks in Programming
See All in Programming
What's New in Android 2026
veronikapj
0
250
Terraform標準の組織で AWS CDKをどう使うか
mu7889yoon
1
490
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
170
AI時代、エンジニアはどう育つのか -未経験エンジニアの成長を間近で見て考えたこと-
thasu0123
0
220
React本体のコードリーディング
high_g_engineer
1
140
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
18k
ソフトウェア設計に溶けるインフラ ― AWS CDK のインフラ認識論
konokenj
3
760
PHP に部分適用が来るぞ!……ところで何それ?おいしいの? #phpcon / phpcon-2026
shogogg
0
580
今さら聞けない .NET CLI
htkym
0
180
<title><a id="</title>君はこのHTMLをパースできるか"></a></title> #雑LT_study
pizzacat83
0
140
作るコストが小さくなった時代 幸せに働くために改めて考えたいこと 〜エンジニアとして価値を出し続けるために注視している二分野〜
yuppeeng
0
190
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
450
Featured
See All Featured
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
930
Documentation Writing (for coders)
carmenintech
77
5.4k
Side Projects
sachag
455
43k
エンジニアに許された特別な時間の終わり
watany
108
250k
Bash Introduction
62gerente
615
220k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.5k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.5k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.7k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
New Earth Scene 8
popppiees
3
2.5k
Transcript
Go のmultiple errors について (2024 年4 月版) syumai Go のエラーハンドリング
最新事情Lunch LT (2024/4/23)
自己紹介 syumai Go Documentation 輪読会 ( 現在は不定期開催) / ECMAScript 仕様輪読会
主催 株式会社ベースマキナで管理画面のSaaS を開発中 Go でGraphQL サーバー (gqlgen) や TypeScript でフロント エンドを書いています Software Design 12 月号からCloudflare Workers の連載をして ます Twitter: @__syumai Website: https://syum.ai
None
ベースマキナとは? DB やAPI の接続設定 & 呼び出し設定をするだけで、簡単にUI 生成が行える管理画面 SaaS API 呼び出しへの権限設定や、レビュー依頼
/ 承認機能も簡単に使えます https://about.basemachina.com
本日話すこと multiple errors についえ multiple errors の基本的な使い方 multiple errors のユースケース
各ライブラリのmultiple errors の対応状況 multiple errors を扱うためのライブラリの紹介
mutiple errors について 本発表では、Go 1.20 で導入された Wrapping multiple errors の機能のことを指し
ます multiple errors と言う用語として何か定義されている訳ではないです https://go.dev/doc/go1.20#errors 複数のエラーをまとめて一つのエラーとして扱えるようにする機能です
multiple errors を扱うためのGo の機能 エラーを一つにまとめる機能 errors.Join fmt.Errorf の "%w" 一つにまとまったエラーを検証するための機能
errors.Is errors.As
エラーを一つにまとめる機能の使い方 errors.Join func A() error { return errorA } func
B() error { return errorB } func F() error { errA := A() errB := B() return errors.Join(errA, errB) }
エラーを一つにまとめる機能の使い方 fmt.Errorf func A() error { return errorA } func
B() error { return errorB } func F() error { errA := A() errB := B() return fmt.Errorf("errA: %w, errB: %w", errA, errB) }
一つにまとまったエラーを検証するための機能 errors.Is var ( errorA = errors.New("error A") errorB =
errors.New("error B") errorC = errors.New("error C") ) func F() error { errA := A() errB := B() return errors.Join(errA, errB) } func main() { err := F() fmt.Println(errors.Is(err, errorA)) // true fmt.Println(errors.Is(err, errorB)) // true fmt.Println(errors.Is(err, errorC)) // false }
一つにまとまったエラーを検証するための機能 errors.As type MyError struct{ Detail string } func (e
*MyError) Error() { ... } func main() { err := F() // return errors.Join(err1, err2) var myErr *MyError if errors.As(err, &myErr) { fmt.Println(myErr.Detail) } }
multiple errors を扱うライブラリを自作するには []error を返す Unwrap メソッドを実装したエラー型を作る type MyError struct
{ errs []error } func (e MyError) Unwrap []error { ... } func (e MyError) Error() string { ... }
multiple errors のユースケース defer errors.Join は nil を無視するので下記のように利用可能 func DoSomething()
(err error) { f, err := os.Open("somefile") if err != nil { return err } defer func() { closeErr := f.Close() // close がerror を返したら、F() の返したerror とJoin して返す err = errors.Join(err, closeErr) }() return F(f) }
multiple errors のユースケース 並行処理結果の待ち受け // https://pkg.go.dev/sync#WaitGroup の例 func FetchURLs() error
{ var wg sync.WaitGroup var urls = []string{ "http://golang.org/", "http://google.com/", "http://example.com/", } var errMu sync.Mutex var err error for _, url := range urls { wg.Add(1) go func(url string) { defer wg.Done() _, fetchErr := http.Get(url) errMu.Lock() err = errors.Join(err, fetchErr) // http.Get で発生した全てのエラーをまとめる errMu.Unlock() }(url) } wg.Wait() return err // まとめたエラーを返す }
サードパーティーライブラリのmultiple errors の対応状況 package status github.com/cockroachdb/errors O github.com/go-errors/errors O github.com/pkg/errors
X github.com/juju/errors X
cockroachdb/errors の例 func A() error { return errorA } func
B() error { return errorB } func F() error { errA := A() errB := B() return errors.Join(errA, errB) } func main() { err := F() fmt.Printf("%+v\n", err) // ちゃんとerror 全体のStacktrace が出る! }
cockroachdb/errors の例 (Stacktrace) // `fmt.Printf("%+v\n", err)` の出力結果 error A (1)
attached stack trace -- stack trace: | main.F | /Users/syumai/go/src/github.com/syumai/til/go/errors/multi-errors/join-cockroach/main.go:26 | main.main | /Users/syumai/go/src/github.com/syumai/til/go/errors/multi-errors/join-cockroach/main.go:30 | runtime.main | /opt/homebrew/Cellar/go/1.22.1/libexec/src/runtime/proc.go:271 Wraps: (2) error A | error B └─ Wraps: (3) attached stack trace -- stack trace: | main.init | /Users/syumai/go/src/github.com/syumai/til/go/errors/multi-errors/join-cockroach/main.go:11 | [...repeated from below...] └─ Wraps: (4) error B └─ Wraps: (5) attached stack trace -- stack trace: | main.init | /Users/syumai/go/src/github.com/syumai/til/go/errors/multi-errors/join-cockroach/main.go:10 | runtime.doInit1 | /opt/homebrew/Cellar/go/1.22.1/libexec/src/runtime/proc.go:7176 | runtime.doInit | /opt/homebrew/Cellar/go/1.22.1/libexec/src/runtime/proc.go:7143 | runtime.main | /opt/homebrew/Cellar/go/1.22.1/libexec/src/runtime/proc.go:253 | runtime.goexit | /opt/homebrew/Cellar/go/1.22.1/libexec/src/runtime/asm_arm64.s:1222 └─ Wraps: (6) error A ...
go-errors/errors の例 func F() error { errA := A() errB
:= B() return errors.Join(errA, errB) } func main() { err := F() // fmt.Printf("%+v\n", err) // go-errors/errors は %+v でStacktrace を出力しない var goErr *errors.Error if errors.As(err, &goErr) { fmt.Println(goErr.ErrorStack()) // errors.As して取得する } }
go-errors/errors の例 (Stacktrace) 片方のerror のStacktrace しか表示されない // `fmt.Println(goErr.ErrorStack())` の出力結果 *errors.errorString
error A /Users/syumai/go/src/github.com/syumai/til/go/errors/multi-errors/join-go-errors/main.go:10 (0x104b579ec) init: errorA = errors.New("error A") /opt/homebrew/Cellar/go/1.22.1/libexec/src/runtime/proc.go:7176 (0x104b04a14) doInit1: f() /opt/homebrew/Cellar/go/1.22.1/libexec/src/runtime/proc.go:7142 (0x104af4fb4) doInit: for _, t := range ts { /opt/homebrew/Cellar/go/1.22.1/libexec/src/runtime/proc.go:253 (0x104af4e9d) main: doInit(m.inittasks) /opt/homebrew/Cellar/go/1.22.1/libexec/src/runtime/asm_arm64.s:1222 (0x104b241d4) goexit: MOVD R0, R0 // NOP
multiple errors を扱うためのライブラリ github.com/uber-go/multierr github.com/hashicorp/go-multierror 上記のいずれも、Go の標準ライブラリがmultiple errors をサポートする前から存在していた もの
Unwrap() []error サポート済みなので、標準ライブラリとの互換性もあります 標準ライブラリのerrors には存在しない機能もあるので興味があれば見てみてください (multiple errors 特化なので、使いどころは選びます)
まとめ Go 1.20 でmultiple errors がサポートされた サードパーティーライブラリでのmultiple errors 対応状況はそれぞれ異なる その上で、Stacktrace
の対応状況も異なる 以前から存在するmultiple errors を扱うためのライブラリは、標準ライブラリのerrors との互換対応済み