2013/07/28

Recent entries from same category

  1. Visual Studio Code で ssh 先のファイルを編集する方法
  2. 虫が入り込むその瞬間
  3. ダウンロードの進捗プログレスバー実装は可能か
  4. sudo コマンド書いた。
  5. Re: Goでコマンドライン引数と環境変数の両方からflagを設定したい

Go言語は例外発生時にdeferを使いrecover()を呼び出す手法で例外補足する事ができ、よくこれは「特殊なので分かり辛い」とか「try/catch/finallyを実装しない理由」と言われる事があります。
確かに一般的な例外補足と比べるとチープに見えたりもします。
なんとなく、以前書いたjsdeferredのGo言語版godeferredを使えば出来るんじゃないかと思ったので書いてみた。
mattn/go-try - GitHub

try/catch/finally for go

https://github.com/mattn/go-try
これを使うとこんな感じに書けます。
Try(func() {
    panic(1)
}).Catch(func(n int) {
    println("int exception:", n)
})
制御構文ではないので、メソッドチェインを使って実現しています。実際にはTry関数からCatchメソッドもしくはFinallyメソッドしか呼び出せないCatchOrFinallyオブジェクトを返しています。CatchメソッドはまたCatchOrFinallyオブジェクトを返すという仕組みですね。いわゆるMaybeモナドといった所でしょうか。
int例外だけでなく
Try(func() {
    panic("foo")
}).Catch(func(s string) {
    println("string exception:", s)
})
string例外や他の型も扱えます。またpanicの例外補足だけでなく
package main

import (
    . "github.com/mattn/go-try/try"
    "fmt"
)

func main() {
    Try(func() {
        v := 0
        println(1 / v)
    }).Catch(func(n int) {
        // not pass
        println("Caught int exception:", n)
    }).Catch(func(s string) {
        // not pass
        println("Caught string exception:", s)
    }).Catch(func(e RuntimeError) {
        fmt.Println("Caught runtime exception:", e)
        for _, st := range e.StackTrace {
            fmt.Printf("  %s:%d\n", st.File, st.Line)
        }
    }).Finally(func() {
        println("finalize")
    })
}
この様なランタイムエラーも補足出きるようになっていて、RuntimeErrorオブジェクトのStackTraceフィールドからスタックトレースも参照出来ます。
ただ残念ながらスタックトレースの行番号は、関数呼び出し位置になるので、上記の例でいうとTryブロックのどの位置で例外が発生してもTry関数の呼び出し位置になってしまっています。
追記
修正しました。こんな感じに出力されます。
Caught runtime exception: runtime error: integer divide by zero
  /home/mattn/dev/go-try/try/foo.go:11
  /home/mattn/dev/go/src/pkg/reflect/value.go:583
  /home/mattn/dev/go/src/pkg/reflect/value.go:433
  /home/mattn/dev/go-try/try/try.go:51
  /home/mattn/dev/go-try/try/foo.go:15
  /home/mattn/dev/go/src/pkg/runtime/386/asm.s:94
  /home/mattn/dev/go/src/pkg/runtime/proc.c:244
finalize

まぁGo言語でちょっとリッチな書き方したいなって人向けです。
# 誰だよそれ

追記
個人的にはネタなので、あまり使わない方が良い気はします。

blog comments powered by Disqus