Łapanie paniki w Golang
W poniższym kodzie, jeśli nie podano argumentu file, w linii 9 panic: runtime error: index out of range
zostanie wywołana panika zgodnie z oczekiwaniami.
Jak mogę "złapać" tę panikę i poradzić sobie z nią, kiedy bezpośrednio przekazując do niej coś (os.Args[1]
), co powoduje panikę? Podobnie jak try / catch w PHP lub try / except w Pythonie.
Szukałem tutaj na StackOverflow, ale nie znalazłem niczego, co by na to odpowiedziało.
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open(os.Args[1])
if err != nil {
fmt.Println("Could not open file")
}
fmt.Printf("%s", file)
}
7 answers
Go nie jest Pythonem, zanim go użyjesz, powinieneś dokładnie sprawdzić czy nie ma args:
func main() {
if len(os.Args) != 2 {
fmt.Printf("usage: %s [filename]\n", os.Args[0])
os.Exit(1)
}
file, err := os.Open(os.Args[1])
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", file)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-07 16:42:05
Program Może odzyskać za pomocą wbudowanej funkcji recover()
:
Oto przykład jak tego użyć:Funkcja
recover
pozwala programowi zarządzać zachowaniem Załóżmy, że funkcjaG
odkłada funkcjęD
, która wywołujerecover
, a panika zachodzi w funkcji na tym samym goroutine, w którejG
jest wykonywana. Gdy uruchamianie funkcji odroczonych osiągnie wartośćD
, wartość zwracana wywołaniaD
dorecover
będzie wartością przekazaną wywołaniupanic
. IfD
zwraca normalnie, bez uruchamiania nowegopanic
, Sekwencja paniki zatrzymuje się. W takim przypadku, stan funkcji wywołanych pomiędzyG
i wywołaniempanic
jest odrzucany, a normalne wykonanie wznawia się. Wszystkie funkcje odroczone przezG
przedD
są następnie uruchamiane, a wykonywanieG
kończy się przez powrót do wywołującego.Wartość zwracana recover jest zerowa, jeśli spełniony jest którykolwiek z poniższych warunków:
panic
's argument wasnil
;- goroutine nie jest panika;
recover
nie został wywołany bezpośrednio przez funkcję odroczoną.
// access buf[i] and return an error if that fails.
func PanicExample(buf []int, i int) (x int, err error) {
defer func() {
// recover from panic if one occured. Set err to nil otherwise.
if (recover() != nil) {
err = errors.New("array index out of bounds")
}
}()
x = buf[i]
}
Zauważ, że częściej niż nie, panika nie jest dobrym rozwiązaniem. Paradygmat Go polega na jawnym sprawdzaniu błędów. Program powinien wpadać w panikę tylko wtedy, gdy okoliczności, w jakich panikuje, nie zdarzają się podczas zwykłego wykonywania programu. Na przykład niemożność otwarcia pliku jest czymś, co może się zdarzyć i nie powinno wywołanie paniki, gdy zabraknie pamięci, jest warte paniki. Niemniej jednak mechanizm ten istnieje po to, aby móc łapać nawet te przypadki i być może zamykać je z wdziękiem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-24 00:04:11
Po pierwsze: nie chciałbyś tego robić. Obsługa błędów w stylu try-catch nie jest obsługą błędów. W Go można sprawdzić len(os.Args)
pierwszy i dostęp do elementu 1 tylko wtedy, gdy jest obecny.
W rzadkich przypadkach musisz złapać panikę (a twoja sprawa jest, a nie jednym z nich!) stosować defer
w połączeniu z recover
. Zobacz http://golang.org/doc/effective_go.html#recover
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-29 21:49:41
Niektóre oficjalne pakiety Golang używają panic/defer+recover jako throw/catch , ale tylko wtedy, gdy wymagają rozwinięcia dużego stosu połączeń. W pakietu JSON Golanga Użyciepanic/defer+recover jakothrow/catch jest najbardziej eleganckim rozwiązaniem.
Z http://blog.golang.org/defer-panic-and-recover
Prawdziwy przykład panic and recover można znaleźć w pakiecie json z biblioteki standardowej Go. Dekoduje Dane zakodowane w JSON z zestawem funkcji rekurencyjnych. W przypadku napotkania wadliwego JSON, parser wywołuje panic, aby rozwinąć stos do najwyższego poziomu wywołania funkcji, która odzyskuje się z panic i zwraca odpowiednią wartość błędu (patrz metody ' error 'I' unmarshal ' typu decodeState w decode.go).
Szukaj d.error(
at http://golang.org/src/encoding/json/decode.go
W twoim przykładzie rozwiązaniem "idiomatycznym" jest sprawdzenie parametry przed ich użyciem, jak wskazywały inne rozwiązania.
Ale, jeśli chcesz / musisz złapać cokolwiek możesz zrobić:
package main
import (
"fmt"
"os"
)
func main() {
defer func() { //catch or finally
if err := recover(); err != nil { //catch
fmt.Fprintf(os.Stderr, "Exception: %v\n", err)
os.Exit(1)
}
}()
file, err := os.Open(os.Args[1])
if err != nil {
fmt.Println("Could not open file")
}
fmt.Printf("%s", file)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-03 15:05:51
Możemy zarządzać paniką bez zatrzymywania procesu za pomocą recover. Wywołanie recover w dowolnej funkcji za pomocą defer zwróci wykonanie do wywołania funkcji. Recover zwraca dwie wartości, jedna to wartość logiczna, a druga to interfejs do odzyskania. Używając twierdzenia typu możemy uzyskać podstawową wartość błędu Możesz również wydrukować błąd podstawowy za pomocą recover.
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("pkg: %v", r)
}
}
}()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-18 10:16:15
Musiałem złapać panikę w walizce testowej. Zostałem przekierowany tutaj.
Func.go
var errUnexpectedClose = errors.New("Unexpected Close")
func closeTransaction(a bool) {
if a == true {
panic(errUnexpectedClose)
}
}
Func_test.go
func TestExpectedPanic() {
got := panicValue(func() { closeTransaction(true) })
a, ok := got.(error)
if a != errUnexpectedClose || !ok {
t.Error("Expected ", errUnexpectedClose.Error())
}
}
func panicValue(fn func()) (recovered interface{}) {
defer func() {
recovered = recover()
}()
fn()
return
}
Używane od https://github.com/golang/go/commit/e4f1d9cf2e948eb0f0bb91d7c253ab61dfff3a59 (ref od VonC)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 09:50:59
Zauważ, że odzyskiwanie leczenia błędu panic Execution (takiego jak próba indeksowania tablicy wyzwalacza poza granicami) może się zmienić z go 1.7 po issue 14965
Runtime: make execution error]}
Make execution panics implementation Error as mandated by Run-time panics (specs) , zamiast panics with strings.
Kiedy Odzyskaj błąd paniki, możesz to zrobić:
if _, ok := recovered.(runtime.Error); !ok {
To jest nadal oceniane, i jako Dave Cheney . wzmianki:
Nie wiem co ludzie obecnie robią, ale z mojego POV to zostało złamane przez długi czas i nikt nie narzekał, więc albo wyraźnie polegają na zepsutym zachowaniu, albo nikogo to nie obchodzi. Tak czy siak myślę, że to dobry pomysł, aby uniknąć tej zmiany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55