Go panic: Difference between revisions
(Created page with "=Internal= * Go Language Error Handling =Overview=") |
|||
(7 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
=Internal= | =Internal= | ||
* [[Go_Language_Error_Handling#panic|Go Language Error Handling]] | * [[Go_Language_Error_Handling#panic|Go Language Error Handling]] | ||
=Recovering after a Panic= | |||
If a function panics, a function executed with <code>defer</code> after the function that panicked can retrieve the argument <code>panic()</code> was called with an restore the normal flow of the program. | |||
<syntaxhighlight lang='go'> | |||
func main() { | |||
defer aRecoveryFunc() | |||
aFuncThatPanics() | |||
} | |||
func aFuncThatPanics() { | |||
fmt.Printf("before panicking ...\n") | |||
panic(fmt.Errorf("I panicked")) | |||
} | |||
func aRecoveryFunc() { | |||
r := recover() | |||
if r == nil { | |||
fmt.Printf("nobody panicked") | |||
} else { | |||
// r is the error the panic was called with | |||
err := r.(error) | |||
fmt.Printf("I recovered this: %s\n", err.Error()) | |||
} | |||
} | |||
</syntaxhighlight> | |||
The result: | |||
<syntaxhighlight lang='text'> | |||
before panicking ... | |||
I recovered this: I panicked | |||
</syntaxhighlight> | |||
=TO PROCESS= | |||
<font color=darkkhaki> | |||
Read and integrate: | |||
* https://go.dev/ref/spec#Run_time_panics | |||
* https://go.dev/ref/spec#Handling_panics | |||
* https://go.dev/blog/defer-panic-and-recover | |||
* https://gabrieltanner.org/blog/golang-error-handling-definitive-guide/#defer-panic-and-recover | |||
* https://learning.oreilly.com/library/view/100-go-mistakes/9781617299599/OEBPS/Text/07.htm#heading_id_3 | |||
Understand this pattern: | |||
<syntaxhighlight lang='go'> | |||
if err := http.ListenAndServe(":8082", nil); err != nil { | |||
panic(err) | |||
} | |||
</syntaxhighlight> | |||
=Overview= | =Overview= | ||
Use panics in truly exceptional cases. | |||
A panic indicates a programmer error (attempting to access an array index out of bounds, writing an uninitialized map, etc.). Panics can also be triggered with: | |||
<syntaxhighlight lang='go'> | |||
panic(<message>) | |||
</syntaxhighlight> | |||
The panic can be caught on the stack outside the function that caused the panic, by executing <code>recover()</code>. Recover can be called in any upper function on the stack, or even if the function that triggers the panic, if the invocation is made with <code>[[Go_Functions#Deferred_Function_Calls|defer]]</code>. | |||
The <code>recover()</code> built-in function allows a program to manage behavior of a panicking goroutine. Executing a call to recover inside a deferred function, but not any function called by it, stops the panicking sequence by restoring normal execution and retrieves the error value passed to the call of panic. If recover is called outside the deferred function it will not stop a panicking sequence. In this case, or when the goroutine is not panicking, or if the argument supplied to panic was <code>nil</code>, recover returns <code>nil</code>. Thus the return value from recover reports whether the goroutine is panicking. | |||
</font> |
Latest revision as of 01:16, 15 March 2024
Internal
Recovering after a Panic
If a function panics, a function executed with defer
after the function that panicked can retrieve the argument panic()
was called with an restore the normal flow of the program.
func main() {
defer aRecoveryFunc()
aFuncThatPanics()
}
func aFuncThatPanics() {
fmt.Printf("before panicking ...\n")
panic(fmt.Errorf("I panicked"))
}
func aRecoveryFunc() {
r := recover()
if r == nil {
fmt.Printf("nobody panicked")
} else {
// r is the error the panic was called with
err := r.(error)
fmt.Printf("I recovered this: %s\n", err.Error())
}
}
The result:
before panicking ...
I recovered this: I panicked
TO PROCESS
Read and integrate:
- https://go.dev/ref/spec#Run_time_panics
- https://go.dev/ref/spec#Handling_panics
- https://go.dev/blog/defer-panic-and-recover
- https://gabrieltanner.org/blog/golang-error-handling-definitive-guide/#defer-panic-and-recover
- https://learning.oreilly.com/library/view/100-go-mistakes/9781617299599/OEBPS/Text/07.htm#heading_id_3
Understand this pattern:
if err := http.ListenAndServe(":8082", nil); err != nil {
panic(err)
}
Overview
Use panics in truly exceptional cases.
A panic indicates a programmer error (attempting to access an array index out of bounds, writing an uninitialized map, etc.). Panics can also be triggered with:
panic(<message>)
The panic can be caught on the stack outside the function that caused the panic, by executing recover()
. Recover can be called in any upper function on the stack, or even if the function that triggers the panic, if the invocation is made with defer
.
The recover()
built-in function allows a program to manage behavior of a panicking goroutine. Executing a call to recover inside a deferred function, but not any function called by it, stops the panicking sequence by restoring normal execution and retrieves the error value passed to the call of panic. If recover is called outside the deferred function it will not stop a panicking sequence. In this case, or when the goroutine is not panicking, or if the argument supplied to panic was nil
, recover returns nil
. Thus the return value from recover reports whether the goroutine is panicking.