Hi there!

In this programming, we will learn what is defer, panic and how to recover from panic

Defer

Defer allows you to postpone the execution of the code and execute it at the moment when there is an exit from the function happening

package main

import "fmt"

func main() {
    defer fmt.Println("Hello!")
    fmt.Println("Bye!")
}
$ go run main.go
Bye!
Hello!

Although the code was supposed to display ``Hello!first,Bye!was displayed first, and only thenHello!`. This is because we have delayed the execution of this code until the main function exits.

Most often, defer is used to clean up resources after use. For example, close a database connection or file after use. Of course, this can be done without defer, but in this case, you need to remember to close the connection after finishing work, and the closing will be far from the opening code

package main

import (
    "io"
    "log"
    "os"
)

func main() {
    file, err := os.Create("file.txt")
    if err != nil {
        log.Fatalln(err)
    }
    _, err = io.WriteString(file, "Writing text to file")
    if err != nil {
        log.Fatalln(err)
    }
    file.Close()
}

Here we close the file using file.Close() at the end of the code that works with the file. If we add defer, the closing can be added immediately after opening. But it will be called in the same way as in the first option

package main

import (
    "io"
    "log"
    "os"
)

func main() {
    file, err := os.Create("file.txt")
    defer file.Close()
    if err != nil {
        log.Fatalln(err)
    }
    _, err = io.WriteString(file, "Writing text to file")
    if err != nil {
        log.Fatalln(err)
    }
}

If we have several defers, they will be called in reverse order

package main

import (
    "fmt"
)

func main() {
    defer fmt.Println(1)
    defer fmt.Println(2)
    defer fmt.Println(3)
}
$ go run main.go
3
2
1

Panic

panic is used in case an error has occurred and you need to stop the program execution

package main

import (
    "fmt"
)

func main() {
    fmt.Println(1)
    panic("Critical Error")
    fmt.Println(2)
}
$ go run main.go
1
panic: Critical Error

goroutine 1 [running]:
main.main()
        /Users/maksym.postument/go/src/github.com/mpostument/hello/main.go:9 +0x6c
exit status 2

Recover

recover allows you to recover from panic and not terminate the program. For this, we will make a separate function called handlePanic, in which recover() will be called. And we will call it using defer in the method in which panic can happen.

package main

import (
    "fmt"
)

func handlePanic() {
    a := recover()

    if a != nil {
        fmt.Println("RECOVER", a)
    }
}

func main() {
    fmt.Println("Start execution")
    runPanic()
    fmt.Println("End of execution")
}

func runPanic() {
    defer handlePanic()
    panic("Critical Error")
}
$ go run main.go
Start execution
RECOVER Critical Error
End of execution

After panic happened. The execution of the program continued smoothly despite the panic

Video