blob: 989cbbef9a4e39d80e84d08e6a1a04f2e553db8c [file] [log] [blame] [view]
Jay C1ac4c942017-04-16 15:53:24 -04001Table of Contents
2=================
3
4+ [Panic](#panic)
5+ [Usage in a Package](#usage-in-a-package)
6+ [References](#references)
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11007
8# Panic
9
Florian Kaiser33a78232015-09-12 18:41:40 +020010The `panic` and `recover` functions behave similarly to exceptions and try/catch in some other languages in that a `panic` causes the program stack to begin unwinding and `recover` can stop it. Deferred functions are still executed as the stack unwinds. If `recover` is called inside such a deferred function, the stack stops unwinding and `recover` returns the value (as an `interface{}`) that was passed to `panic`. The runtime will also panic in extraordinary circumstances, such as indexing an array or slice out-of-bounds. If a `panic` causes the stack to unwind outside of any executing goroutine (e.g. `main` or the top-level function given to `go` fail to recover from it), the program exits with a stack trace of all executing goroutines. A `panic` cannot be `recover`ed by a different goroutine.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110011
12# Usage in a Package
13
Florian Kaiser33a78232015-09-12 18:41:40 +020014By convention, no explicit `panic()` should be allowed to cross a package boundary. Indicating error conditions to callers should be done by returning error value. Within a package, however, especially if there are deeply nested calls to non-exported functions, it can be useful (and improve readability) to use panic to indicate error conditions which should be translated into error for the calling function. Below is an admittedly contrived example of a way in which a nested function and an exported function may interact via this panic-on-error relationship.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110015
Florian Kaiser130898a2015-09-12 18:38:08 +020016```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110017// A ParseError indicates an error in converting a word into an integer.
18type ParseError struct {
Dave Day0d6986a2014-12-10 15:02:18 +110019 Index int // The index into the space-separated list of words.
20 Word string // The word that generated the parse error.
21 Error error // The raw error that precipitated this error, if any.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110022}
23
24// String returns a human-readable error message.
25func (e *ParseError) String() string {
Dave Day0d6986a2014-12-10 15:02:18 +110026 return fmt.Sprintf("pkg: error parsing %q as int", e.Word)
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110027}
28
l0stman6a42c36e2017-05-10 08:38:40 +030029// Parse parses the space-separated words in input as integers.
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110030func Parse(input string) (numbers []int, err error) {
Dave Day0d6986a2014-12-10 15:02:18 +110031 defer func() {
32 if r := recover(); r != nil {
33 var ok bool
34 err, ok = r.(error)
35 if !ok {
36 err = fmt.Errorf("pkg: %v", r)
37 }
38 }
39 }()
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110040
Dave Day0d6986a2014-12-10 15:02:18 +110041 fields := strings.Fields(input)
42 numbers = fields2numbers(fields)
43 return
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110044}
45
46func fields2numbers(fields []string) (numbers []int) {
Dave Day0d6986a2014-12-10 15:02:18 +110047 if len(fields) == 0 {
48 panic("no words to parse")
49 }
50 for idx, field := range fields {
51 num, err := strconv.Atoi(field)
52 if err != nil {
53 panic(&ParseError{idx, field, err})
54 }
55 numbers = append(numbers, num)
56 }
57 return
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110058}
59```
60
61To demonstrate the behavior, consider the following main function:
Florian Kaiser130898a2015-09-12 18:38:08 +020062```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110063func main() {
Dave Day0d6986a2014-12-10 15:02:18 +110064 var examples = []string{
65 "1 2 3 4 5",
66 "100 50 25 12.5 6.25",
67 "2 + 2 = 4",
68 "1st class",
69 "",
70 }
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110071
Dave Day0d6986a2014-12-10 15:02:18 +110072 for _, ex := range examples {
73 fmt.Printf("Parsing %q:\n ", ex)
74 nums, err := Parse(ex)
75 if err != nil {
76 fmt.Println(err)
77 continue
78 }
79 fmt.Println(nums)
80 }
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110081}
82```
83
84# References
Baiju Muthukadanf73d5462016-02-25 10:09:44 +053085[Defer, Panic and Recover](https://blog.golang.org/defer-panic-and-recover)
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110086
Baiju Muthukadanf73d5462016-02-25 10:09:44 +053087https://golang.org/ref/spec#Handling_panics
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110088
Baiju Muthukadanf73d5462016-02-25 10:09:44 +053089https://golang.org/ref/spec#Run_time_panics