A panic signals that execution cannot safely continue, often because of a programmer error or an unexpected state. Unlike an ordinary error, it does not wait for a caller to check a return value: Go unwinds the current function stack looking for recovery. If none occurs, the program terminates and reports a stack trace. Use panics sparingly; return errors when a caller can reasonably handle the failure. section 4.3.1 section 4.3
Listing 4.10 Error and panic
package main
import (
"errors"
"fmt"
)
var ErrDivideByZero = errors.New("Can't divide by zero")
func main() {
fmt.Println("Divide 1 by 0") #1
_, err := precheckDivide(1, 0) #1
if err != nil { #1
fmt.Printf("Error: %s\n", err) #1
} #1
fmt.Println("Divide 2 by 0") #2
divide(2, 0) #2
}
func precheckDivide(a, b int) (int, error) { #3
if b == 0 {
return 0, ErrDivideByZero
}
return divide(a, b), nil
}
func divide(a, b int) int { #4
return a / b
}
Compare a checked division that returns an error with an unchecked division that panics. section 4.3.1
Call panic with an error value when deliberately reporting an unrecoverable condition. Although panic accepts other values, an error gives a recovery function something useful to inspect or return. Recovery belongs in a deferred function: recover retrieves the panic value and stops further unwinding. Put that boundary where the application can make a deliberate decision about what happens next. section 4.3.2 section 4.3.4
Convert a known panic at a function boundary
This complete example turns a deliberately raised error-valued panic into a returned error: package main import ( "errors" "fmt" ) func runJob() (err error) { defer func() { if value := recover(); value != nil { err = value.(error) } }() panic(errors.New("job cannot continue")) } func main() { if err := runJob(); err != nil { fmt.Println(err) } } The type assertion relies on runJob's known panic value being an error; panic can also carry other values. section 4.3.2 section 4.3.4
A goroutine has its own function stack. A panic there cannot reach a recover deferred by the function that launched it; if it goes unhandled on the goroutine's stack, it terminates the program. Place recovery inside a worker that might panic, or wrap launched work in a function that defers recovery. A connection handler can also close its connection in that deferred function. section 4.3.5
Listing 4.20 Handling panics on a goroutine
func handle(conn net.Conn) {
defer func() { #1
if err := recover(); err != nil { #1
fmt.Printf("Fatal error: %s", err) #1
} #1
conn.Close() #1
}() #1
reader := bufio.NewReader(conn) #1
data, err := reader.ReadBytes('\n')
if err != nil {
fmt.Println("Failed to read from socket.")
}
response(data, conn)
}
func response(data []byte, conn net.Conn) {
conn.Write(data)
panic(errors.New("Pretend I’m a real error")) #2
}
The connection handler places recover and connection cleanup in the goroutine that runs the handler. section 4.3.5







