2013-10-29 3 views
6

go実行時にpanic(nil)が検出され、エラーが報告されます。遅延関数でパニック(nil)と通常の実行を検出する方法Go?

しかし、nilを返すので、私はdefer赤関数で​​recover()panic(nil)を検出できないので、私はゼロであることが ためrecover()の戻り値をテストすることになるように私は通常の実行(NOパニック)と区別することができません。

例えば、

defer func(){ 
    var err = recover() 
    if err != nil { 
     // Real serious situation. Panic from inner code. 
     // And we may have some critical resources which 
     // must be cleaned-up at any cases. 
     // However, this will not be executed for panic(nil) 

     rollback() 

     // I am still not sure that how should I treat `panic`… 
     // Should I just ignore them? 
    } 
}() 

var err = doTransaction() 
if err == nil { 
    commit() // Happy case. 
} else { 
    rollback() // Regular execution. Just a lucky case. 
} 

ROLLBACKは単なる一例であり、私は重要な例はたくさんのクリーンアップを必要とすることができますと思います。まあ、これらのクリーンアップコードは実際のプログラムのクラッシュでも実行されませんが、私は可能な限り防御したいと思います。

遅延関数のパラメータに関係なく、どのようにパニックを検出することができますか?

答えて

4

質問が間違っていない限り、遅延ファンクションコールは、値がnilだったとしても、パニック時にが実行されます。これはfollowing programによって示されている:

package main 

import "fmt" 

func main() { 
    defer func() { 
     fmt.Println("Recover:", recover()) 
    }() 
    panic(nil) 
} 

panic(nil)nilrecover()によって返された値を比較することで起こった場合は、したがって、簡単に検出することができます。

編集のコメントに編集:

はい、そうです。遅延呼び出しは通常、関数が戻るときに実行されます。しかし、panic()の後にコールスタックを巻き戻すときにも実行されます。質問の後

編集が更新されました:

あなたはこれらのケースを区別する方法がないことを正しいです。一方、nilでのパニックはあまり意味がありません。特にこの制限のためです。

panic(nil)の唯一の使用例は、意図的にリカバリを回避し、スタックトレースでプログラムを強制的にクラッシュさせることです。しかし、例えばruntimeパッケージを使用すると、これを行うもっとエレガントな方法があります。

+0

ああ、不明な質問がありましたら申し訳ありません。私が望んでいたのは、 'パニック(無)'と '遅延関数'での通常の実行を区別することでした... – Eonil

+0

多分、関数を終了する前にフラグを設定することができます。 – Eonil

+0

インスピレーションをありがとう!私はフラグを設定することでこれを解決しました。 – Eonil

2

私は単に終了する前にフラグを設定できます。

AFAIK、パニックはゴルーチン固有であり、シングルゴルーチンはシングルスレッドであることが保証されています。したがって、変数okでは同期/ロックは不要です。私が間違っているなら、私を修正してください。

func clean(ok *bool) { 
    if *ok { 
     log.Printf("Execution OK. No panic detected.\n") 
    } else { 
     var reason = recover() 
     log.Printf("Some bad thing happen. reason = %v\n", reason) 
     panic("Abnormal exit. Program abandoned. Stack-trace here.") 
     debug.PrintStack() // Oops. this will not run. 
    } 
} 

func main() { 
    var ok bool = false 

    defer clean(&ok) 
    panic(nil) 

    test1() // Here's the main job. 

    ok = true 
    log.Printf("All work done. Quit gracefully.\n") 
} 
+0

エラー処理の最後の手段である**パニック**が予期されるかどうかを決定するフラグを使用することは何ですか?実際に何を達成しようとしていますか?これは多くのレベルで間違っているようです。 – nemo

+0

@nemo私の場合、何らかの 'panic()'が何らかの理由で起こった場合、ブロックで実行されたSQLコマンドをロールバックするためにこれが必要でした。私はこれが古典的なものだと思う。いくつかの機能については何の保証もないので、決してパニックにはならない。 – Eonil

+0

質問をこの情報で更新し、なぜパニックに陥っているのか説明してください。 – nemo

関連する問題