Slide 1

Slide 1 text

Go1.13 以後の エラーハンドリング について語ろう Go Conference 2019 Autumn, Oct 28 2019 Koya IWAMURA CyberAgent, Inc. @cia_rana

Slide 2

Slide 2 text

Go1.13 からスタックトレースをとるための機能が追加 ● fmt.Errorf (%w) ● errors.Is ● errors.As ● errors.Unwrap

Slide 3

Slide 3 text

fmt.Errorf (%w) ● 既存のエラーをラッピング ● 情報を付加 func MyFunc() error { err := f() return fmt.Errorf(“MyFunc: %w”, err) }

Slide 4

Slide 4 text

errors.Is ● 値の比較 if err == sql.ErrNoRows { fmt.Println(err) } if errors.Is(err, sql.ErrNoRows) { fmt.Println(err) } Go1.13〜

Slide 5

Slide 5 text

errors.As ● 型の比較(assertion, switch)、キャプチャ if e, ok := err.(*url.Error); ok { fmt.Printf(“isTimeout: %v”, e.Timeout()) } var e *url.Error if errors.As(err, &e) { fmt.Printf(“isTimeout: %v”, e.Timeout()) } Go1.13〜

Slide 6

Slide 6 text

Go1.13以後 エラーハンドリングする上での留意点

Slide 7

Slide 7 text

01 `if err != nil` が 無力化される Go1.13以後 エラーハンドリングする上での留意点

Slide 8

Slide 8 text

`if err != nil` が無力化される func f() ([]byte, error) { resp, err := http.Get("cyberagent.ai") if err != nil { return nil, err } return ioutil.ReadAll(resp.Body) } func main() { a, err := f() if err != nil { fmt.Println(err) } fmt.Println(string(a)) }

Slide 9

Slide 9 text

`if err != nil` が無力化される func f() ([]byte, error) { resp, err := http.Get("cyberagent.ai") if err != nil { return nil, err } a, err := ioutil.ReadAll(resp.Body) return a, fmt.Errorf(“%w”, err) } func main() { a, err := f() if err != nil { fmt.Println(err) } fmt.Println(string(a)) }

Slide 10

Slide 10 text

`if err != nil` が無力化される func f() ([]byte, error) { resp, err := http.Get("cyberagent.ai") if err != nil { return nil, err } a, err := ioutil.ReadAll(resp.Body) return a, fmt.Errorf(“%w”, err) } func main() { a, err := f() if err != nil { fmt.Println(err) } fmt.Println(string(a)) } errがnilでも・・・

Slide 11

Slide 11 text

`if err != nil` が無力化される func f() ([]byte, error) { resp, err := http.Get("cyberagent.ai") if err != nil { return nil, err } a, err := ioutil.ReadAll(resp.Body) return a, fmt.Errorf(“%w”, err) } func main() { a, err := f() if err != nil { fmt.Println(err) } fmt.Println(string(a)) } errがnilでも・・・ if文の中が走っちゃう

Slide 12

Slide 12 text

`if err != nil` が無力化される func f() ([]byte, error) { resp, err := http.Get("cyberagent.ai") if err != nil { return nil, err } a, err := ioutil.ReadAll(resp.Body) return a, fmt.Errorf(“%w”, err) } func main() { a, err := f() if errors.Is(err, nil) { fmt.Println(err) } fmt.Println(string(a)) } errors.Isを使おう!

Slide 13

Slide 13 text

02 xerrorsと同じ挙動に 見せかけて実は違う Go1.13以後 エラーハンドリングする上での留意点

Slide 14

Slide 14 text

xerrorsと同じ挙動に見せかけて実は違う https://github.com/golang/go/wiki/ErrorValueFAQ

Slide 15

Slide 15 text

xerrorsと同じ挙動に見せかけて実は違う xerrors.Errorfでは ラップした位置に関する情報をとれる

Slide 16

Slide 16 text

xerrorsと同じ挙動に見せかけて実は違う fmt.Errorf では ラップした位置に関する情報をとれない

Slide 17

Slide 17 text

xerrorsと同じ挙動に見せかけて実は違う xerrors.Errorf で error をラップするには フォーマット指示子を ”: %w” にして 末尾に持ってこなくてはならない xerrors.Errorf(“MyError: %w”, err)

Slide 18

Slide 18 text

xerrorsと同じ挙動に見せかけて実は違う fmt.Errorf で error をラップするには フォーマット指示子が ”%w” でありさえすれば良い fmt.Errorf(“MyError: %w in main.main”, err)

Slide 19

Slide 19 text

Thank you for listening!