A simple introduction to panic-recover in Golang

164 阅读1分钟
请注意,本文为作者原创。
Please notice that this article is created by the author myself originally.

Golang does not have try-catch as that is in java or php. but instead, it has panic and recover mechanism to let developer process the panic in another place. For exmaple, you may write code like this to process a panic error:

package main

import "fmt"

func defer1() {
	action := recover()
	fmt.Println("I am defer1", action)
}

func defer2() {
	action := recover()
	fmt.Println("I am defer2", action)
}

func main() {
	defer defer1()
	defer defer2()

	panic("PANIC")

}

and you may know that the defer functions are executed in FILO(first-in, last-out) order, so the second call of recover will return nothing but nil. This is the first thing we should keep in mind when programming with Golang, and the second point is, if a panic happens in one goroutine, the other goroutine can recover something? show the code,

package main

import (
	"fmt"
	"sync"
)

func defer1() {
	if r := recover(); r != nil {
		fmt.Println("i am defer1, ", r)
	}
}

func defer2() {
	if r := recover(); r != nil {
		fmt.Println("i am defer2, ", r)
	}
}

func worker(wg *sync.WaitGroup) {
	defer wg.Done()
	defer defer2()
	fmt.Println("i am the worker routine.")
	panic("PANIC in worker")
}

func main() {
	defer defer1()
	defer defer2()

	var wg sync.WaitGroup
	wg.Add(1)
	go worker(&wg)
	wg.Wait()
}

when panic happens in the worker goroutine, the recover call in defer2 of worker goroutine can return the panic error string, by contrast, the recover call in defer2 in main goroutine returns nothing but nil. So panic-recover mechanism is only valid in current goroutine. But the defer2 and defer1 in main are still called as normal, the recover call in them only returns nil.
Although the above talked panic-recover is used in explicit goroutine context, it can also be exploited just within a function in a single goroutine, this is the example,

package main

import "fmt"

func worker() {
	defer defer2()
	fmt.Println("This is the worker function.")
	panic("PANIC2")
}

func defer1() {
	if r := recover(); r != nil {
		fmt.Println("I am the defer1", r)
	}
}

func defer2() {
	if r := recover(); r != nil {
		fmt.Println("I am the defer2", r)
	}
}

func main() {
	defer defer1()
	worker()
	panic("PANIC")
}

and the output below may be conformed to your expectation,

This is the worker function.
I am the defer2 PANIC2
I am the defer1 PANIC

ok, that's all, enjoy it.