Go Basic: Understanding Error Handling: Errors, Panic, Defer, Recover in Go

Let’s dive into our lesson on Error Handling in Go. This format of approach might look unique to you if you’re coming from a language that uses exceptions for handling errors.

full lessons here👇:
https://programmerscareer.com/zh-cn/golang-basic-skill/

Generated by AI, there may be errors, for reference only

Topic: Error Handling

Go doesn’t have the conventional try-catch-finally idiom seen in languages like Java and Python. Go encourages programmers to think about errors as just another type of result that a function can return.

A function either returns a result or an error, represented as follows:

1
2
3
func openFile(fileName string) (file *File, err error) {  
// …
}

Here, err is an error type. It is a built-in interface:

1
2
3
type error interface {  
Error() string
}

Any type that defines the Error() string method is said to satisfy the errorinterface. In case of failure, the function returns nil for the file and an error value for the err.

To check for an error after calling a function:

1
2
3
4
5
6
file, err := openFile("testfile")  
if err != nil {
// handle the error and return
return
}
// continue processing file

Panic

Panic is a function that stops the ordinary flow of control. When a function encounters a panic, its execution stops, any deferred functions are executed and then it returns to its caller.

1
panic("a problem occurred")

This approach stops the execution of the current function and starts to unwind the stack of the goroutine, running any deferred functions along the way.

Defer

Defer keyword allows us to postpone the execution of a function or method or an anonymous method until the end of the current function execution:

1
2
3
4
func worker() {  
defer fmt.Println("The worker has stopped")
fmt.Println("The worker is working")
}

In this case, the message “The worker has stopped” would be printed after the message “The worker is working”, even though in the code it precedes it.

Recover

Recover is a function that regains control of a panicking goroutine. Recover is only useful inside deferred functions. During normal execution, a call to recover will return nil and have no other effect. If the current goroutine is panicking, a call to recover will capture the value given to panic and resume normal execution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func except() {  
if r := recover(); r!= nil {
fmt.Println("Recovered", r)
}
}
func paycheck(amount int) {
defer except()
if amount>0 {
fmt.Println(amount)
} else {
panic("Your paycheck is negative!")
}
}
func main() {
paycheck(1000)
fmt.Println("This message will still print.")
paycheck(-1000)
fmt.Println("This message will not.")
}

In this case, recover captures the panic and allows the program to continue its execution.

Topics: Error Handling continuation — Panic and Recover

A panic typically means something went unexpectedly wrong. Mostly we use it to fail fast on errors that shouldn’t occur during normal operation, or that we aren’t prepared to handle gracefully.

Here’s an example:

1
2
3
4
5
6
7
8
9
10
package main

import "os"

func main() {
_, err := os.Create("/tmp/file")
if err != nil {
panic(err)
}
}

In the above example, we use panic to check for unexpected errors when creating a new file.

A common use of panic is to abort if a function returns an error value that we don’t know how to (or want to) handle.

Now let’s talk about recover.

recover is a function that regains control of a panicking goroutine. recover is only useful inside deferred functions. During normal execution, a recover will return nil and will have no other effect. If the current goroutine is panicking, a call to recover will capture the value given to panic and resume normal execution.

Unlike other languages like Python and Java, errors are just values in Go and hence can be programmed to recover from it.

Let’s look at an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main  

import "fmt"

func myFunction() {
defer func() {
r := recover()
if r != nil {
fmt.Println("Recovered from", r)
}
}()
a, b := 10, 0
c := a / b
fmt.Println(c)
}

func main() {
myFunction()
fmt.Println("I am back in main.")
}

In the above example, we try to divide a number by 0 which usually would cause a panic. But we recover from it within the function and execute the next line in main.

English post: https://programmerscareer.com/go-basic-05/
作者:Wesley Wei – Twitter Wesley Wei – Medium
注意:本文为作者原创,转载请注明出处。

Go Basic: Understanding Atomic, Mutex, Stateful Goroutines in Go Go Basic: Understanding Methods, Interfaces, Struct Embedding, Generics: Covering OOP concepts in Go

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×