2013-10-29 10 views
6

Die Go Runtime kann panic(nil) erkennen und meldet einen Fehler.Wie erkennt man Panik (Null) und normale Ausführung in der verzögerten Funktion?

Allerdings kann ich nicht panic(nil) mit recover() in einer defer roten Funktion erkennen, weil es nil zurück, so kann ich es nicht von den normalen Ausführung unterscheiden (keine Panik), wie ich für der Rückgabewert von recover() testen würde Null sein .

Zum Beispiel

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 ist nur ein Beispiel, und ich glaube, ich kann viel kritischen Fällen muss Bereinigungs haben. Nun, dieser Cleanup-Code wird auch bei einem echten Programmabsturz nicht ausgeführt, aber ich möchte so viel wie möglich verteidigen.

Wie kann ich eine Panik unabhängig von ihrem Parameter in einer verzögerten Funktion erkennen?

Antwort

4

Wenn ich Ihre Frage nicht falsch verstanden habe, werden die verzögerten Funktionsaufrufe ausgeführt, wenn Sie in Panik geraten, auch wenn der übergebene Wert nil war. Dies wird durch die following program dargestellt:

package main 

import "fmt" 

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

Sie können daher leicht erkennen, ob panic(nil) geschehen, indem der Wert verglichen mit recover()-nil zurückgegeben.

Kommentar bearbeiten zu beantworten:

Ja, das ist wahr; Zurückgestellte Aufrufe werden normalerweise ausgeführt, wenn eine Funktion zurückkehrt. Sie werden aber auch beim Abwickeln des Call-Stacks nach einer panic() ausgeführt.

bearbeiten nach Frage wurde aktualisiert:

Sie sind richtig, dass es keine Möglichkeit, diese Fälle zu unterscheiden ist. Auf der anderen Seite macht Panik mit nil nicht viel Sinn - vor allem wegen dieser Einschränkung.

Der einzige Anwendungsfall für panic(nil), den ich denken könnte, wäre, die Wiederherstellung absichtlich zu vermeiden und das Programm zum Absturz mit einem Stack-Trace zu zwingen. Es gibt elegantere Möglichkeiten, dies zu tun, zum Beispiel das runtime Paket.

+0

Ah Es tut mir leid für die unklare Frage. Was ich wollte, war die Unterscheidung von "panic (nil)" und normaler Ausführung in "defer'red" -Funktion ... – Eonil

+0

Vielleicht kann ich einfach ein Flag setzen, bevor ich die Funktion verlasse. – Eonil

+0

Danke für die Inspiration! Ich habe das gelöst, indem ich eine Flagge gesetzt habe. – Eonil

2

Ich kann einfach eine Flagge vor dem Ausgang setzen.

AFAIK, Panik ist Goroutine-spezifische, und einzelne Goroutine ist garantiert in Einzel-Thread. Daher ist keine Synchronisation/Verriegelung um die Variable ok erforderlich. Wenn ich falsch liege, korrigiere mich bitte.

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

Was nutzt eine Flagge, die darüber entscheidet, ob eine ** Panik **, der letzte Ausweg bei der Fehlerbehandlung, erwartet wird oder nicht? Was versuchst du eigentlich zu erreichen? Dies scheint auf vielen Ebenen falsch zu sein. – nemo

+0

@nemo In meinem Fall brauchte ich das, um irgendeinen SQL-Befehl, der in einem Block ausgeführt wurde, zu ROLLBACK zu machen, wenn irgendwelche 'panic()' aus irgendeinem Grund passieren. Ich denke, das ist klassisch * try..catch..clean und strike * Strategie.Da gibt es keine Garantie für eine Funktion * nie Panik * innen ... Jede bessere Idee? – Eonil

+0

Bitte aktualisieren Sie Ihre Frage mit diesen Informationen und erklären Sie, warum Sie keine Panik haben. – nemo