$30 off During Our Annual Pro Sale. View Details »

Go1.13以後のエラーハンドリングについて語ろう / Let's talk about error handling after Go 1 13

Go1.13以後のエラーハンドリングについて語ろう / Let's talk about error handling after Go 1 13

Koya IWAMURA

October 28, 2019
Tweet

More Decks by Koya IWAMURA

Other Decks in Programming

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  5. 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〜

    View Slide

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

    View Slide

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

    View Slide

  8. `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))
    }

    View Slide

  9. `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))
    }

    View Slide

  10. `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でも・・・

    View Slide

  11. `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文の中が走っちゃう

    View Slide

  12. `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を使おう!

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  19. Thank you
    for listening!

    View Slide