Ich muss verwenden defer
, um Zuordnungen freizugeben, die manuell mit der C
Bibliothek erstellt wurden, aber ich muss auch os.Exit
irgendwann den Status ungleich 0 haben. Der schwierige Teil ist, dass os.Exit
jede zurückgestellte Anweisung übersprungen wird:
package main
import "fmt"
import "os"
func main() {
// `defer`s will _not_ be run when using `os.Exit`, so
// this `fmt.Println` will never be called.
defer fmt.Println("!")
// sometimes ones might use defer to do critical operations
// like close a database, remove a lock or free memory
// Exit with status code.
os.Exit(3)
}
Spielplatz: http://play.golang.org/p/CDiAh9SXRM gestohlen von https://gobyexample.com/exit
Wie kann man ein Go-Programm beenden, das deklarierte defer
Anrufe berücksichtigt? Gibt es eine Alternative zu os.Exit
?
os.Exit
: play.golang.org/p/IsSI9VB7j8os.Exit
nachdem ich andere Operationen ausgeführt habe, die ebenfalls etwas aufschieben ... lassen Sie mich etwas mehr darüber nachdenken.defer
inmain
Kombination mitos.Exit
ist definitiv eine raue Stelle. Eine Architektur wie @Rob Napier ist ein besserer Weg.Antworten:
runtime.Goexit()
ist der einfache Weg, dies zu erreichen.Jedoch:
Wenn Sie es also von der Hauptgoroutine aus aufrufen,
main
müssen Sie oben hinzufügendefer os.Exit(0)
Darunter möchten Sie möglicherweise einige andere
defer
Anweisungen hinzufügen , die die anderen Goroutinen anweisen, anzuhalten und aufzuräumen.quelle
runtime.Goexit()
existiert. Ist das aus einer neueren Version?Bewegen Sie Ihr Programm einfach um eine Ebene nach unten und geben Sie Ihren Exit-Code zurück:
package main import "fmt" import "os" func doTheStuff() int { defer fmt.Println("!") return 3 } func main() { os.Exit(doTheStuff()) }
quelle
defer
insidefunc main
oder eine Funktion verwenden, die beendet wird?os.Exit()
an zufälligen Stellen im Code zu verwenden. Dies macht das Testen neben dem Problem der Fehlercodes sehr schwierig. Die Lösung von peterSO, die @ctcherry verlinkt, ist in Ordnung, lässt sich aber IMO nicht gut auf ein größeres Programm skalieren. Sie müssten dascode
globale machen. Ich glaube, Sie sollten main () ziemlich einfach halten und sich nur um die Dinge auf Betriebssystemebene kümmern (wie den endgültigen Statuscode).Nach einigen Recherchen auf diese verweisen dies , fand ich eine Alternative , dass:
Wir können die Vorteile der
panic
undrecover
. Es stellt sich heraus, dass Anrufepanic
von Natur ausdefer
honoriert werden, aber auch immer mit einem Nicht-0
Statuscode beendet werden und eine Stapelverfolgung ausgegeben wird. Der Trick ist, dass wir den letzten Aspekt des Panikverhaltens überschreiben können mit:package main import "fmt" import "os" type Exit struct{ Code int } // exit code handler func handleExit() { if e := recover(); e != nil { if exit, ok := e.(Exit); ok == true { os.Exit(exit.Code) } panic(e) // not an Exit, bubble up } }
Um ein Programm zu einem beliebigen Zeitpunkt
defer
zu beenden und dennoch alle deklarierten Anweisungen beizubehalten, müssen Sie nur einenExit
Typ ausgeben :func main() { defer handleExit() // plug the exit handler defer fmt.Println("cleaning...") panic(Exit{3}) // 3 is the exit code }
Es ist kein Refactoring erforderlich, außer dass eine Leitung eingesteckt wird
func main
:func main() { defer handleExit() // ready to go }
Dies lässt sich mit größeren Codebasen recht gut skalieren, sodass ich es zur Überprüfung zur Verfügung stellen werde. Ich hoffe es hilft.
Spielplatz: http://play.golang.org/p/4tyWwhcX0-
quelle
handleExit
Anruf auch bei normalem Ausgang getätigt wird? Ref: play.golang.org/p/QDJum4kOXk entfernen Sie den Kommentar//panic
und sehen Sie den Unterschied.Für die Nachwelt war dies für mich eine elegantere Lösung:
func main() { retcode := 0 defer func() { os.Exit(retcode) }() defer defer1() defer defer2() [...] if err != nil { retcode = 1 return } }
quelle
Ich würde vorschlagen, eine Goroutine zu verwenden
func main(){ fmt.Println("Hello world") go func(){ os.Exit(0) } }
quelle