確かに一般的な例外補足と比べるとチープに見えたりもします。
なんとなく、以前書いた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フィールドからスタックトレースも参照出来ます。追記
修正しました。こんな感じに出力されます。
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言語でちょっとリッチな書き方したいなって人向けです。
# 誰だよそれ
追記
個人的にはネタなので、あまり使わない方が良い気はします。