Defer, panic and recover in Go

 This is a study note for YouTube: https://www.youtube.com/watch?v=YS4e4q9oBaU&t=12079s

Except conditional statement and looping, you can also use defer, panic and recover to manage control flow in Go.

Defer

You can use "defer" keyword to defer the execution of a function when the calling function exits but before it returns. For example:

func main() {
fmt.Println("Start!")
defer fmt.Println("Middle!")
fmt.Println("End!")
}
The result is:
Start! End! Middle!

Deferred functions are executed in LIFO (Last In First Out) order. For exampe:

func main() {
defer fmt.Println("Start!")
defer fmt.Println("Middle!")
defer fmt.Println("End!")
}

The result is:

End! Middle! Start!

Defer function is very useful, one example is that you can use refer function to do some connection closing, resource clean up tasks. For example, in below code, you can put a close function right after you establish the connection before you even start to use the connection. This is because the close function is deferred, it will only execute after the calling function exits.

func main() {
res, err := http.Get("http://www.google.com/robots.txt")
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
robots, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%ss\n", robots)
}

Another important thing to mention is that the deferred functions only take the variable value from the time is deferred, the change after the deferred function call will not impact the input value in the deferred function. For example:

func main() {
a := "start"
defer fmt.Println(a)
a = "end"
}

The result is:

start

You can see that the value is still "start" even though variable "a" was changed to "end" later.

Panic

Panic is kinda like Exception in other programming language like JAVA. When panic function is executed, it will log the the position where causes the panic and then exit.

func main() {

fmt.Println("start")
panic("something bad happened")
fmt.Println("end")
}

The result is:

(base)MyLaptop$ go run src/github.com/mingdos/firstapp/Main.go
start
panic: something bad happened
goroutine 1 [running]:
main.main()
       /Users/caimingda/go/src/github.com/mingdos/firstapp/Main.go:10 +0x95

exit status 2

When works with deferred function, The execution order is like below:

Normal execution -> (defer function calling) -> normal execution -> (panic happens) -> defer function execution -> panic function execution

func main() {

fmt.Println("start")
    defer fmt.Println("this was deferred")
panic("something bad happened")
fmt.Println("end")
}

The result is:

(base)MyLaptop$ go run src/github.com/mingdos/firstapp/Main.go
start
this was deferred
panic: something bad happened

goroutine 1 [running]:
main.main()
       /Users/caimingda/go/src/github.com/mingdos/firstapp/Main.go:11 +0x95

exit status 2



Recover

In defer function, you can call recover() function to check if the current program is panic. The recover() function return nil if the program is not panic, and it will return the error message when it is panic.
func main() {

fmt.Println("start")
defer func() {
if err := recover(); err != nil {
fmt.Println("Error: ", err)
}
}()
panic("something bad happened")
fmt.Println("end")
}

The result is:

start Error: something bad happened

The recover() function does more than this actually. It will recover the execution from where after the caller function who cause the panic inside and continue to execute the rest.

func main() {

fmt.Println("start")
panicer()
fmt.Println("end")
}

func panicer() {
fmt.Println("about to panic")
defer func() {
if err := recover(); err != nil {
fmt.Println("Error: ", err)
}
}()
panic("something bad happened")
fmt.Println("Done panic")
}

The result is:

start about to panic Error: something bad happened end

If the defer function don't know how to handle the panic, it actually can redo a panic when it detect a panic. In this way, the caller function will still have the panic.


Reference: https://www.youtube.com/watch?v=YS4e4q9oBaU&t=12079s

Comments

Popular posts from this blog

Basic understanding of TLS-PSK protocol

Differences between ASIC, ASSP and ASIP

Orthogonal instruction set