This is the 30th day of my participation in the Wenwen Challenge

If ❤️ my article is helpful, welcome to like, follow. This is the biggest encouragement for me to continue my technical creation. More previous articles in my personal column

Let’s try Golang and put a try catch in it

preface

Golang has many advantages: static compilation, coroutines, and high performance comparable to C. But there’s also something outrageous about the often derided five-line, three-line exception error handling, and here’s where the problem arises

func readFile(path string) ([]byte, error) {
    file, err := os.Open(path)
    iferr ! =nil {
        return nil, err
    }
    defer file.Close()
    return ioutil.ReadAll(file)
}
Copy the code

The readFile function reads out the contents of the specified file itself and returns it, reporting immediately to the caller when an error occurs. According to the Golang programming paradigm, every function that can cause an error should return error as the last value, so Golang code is littered with “If err! = nil” statement. Five lines of code, three lines of error handling jokes became popular

Can we try and catch

I’ve been used to try catch handling since I used Python and PHP. Therefore, I have been annoyed by Golang’s use of process control with panic() and recover(). In order to be comfortable in the future, I will implement the original try catch error handling method today

The Golang language has the recover() function as an outage recovery mechanism, allowing programs to recover in goroutine during outages.

So we can use the recover() function as a hook to determine whether the program is present or not. It calls our exception handler when an exception occurs. Let’s start with a simple implementation:

package main

import "fmt"

func try(userFn func(a)) {
	defer func(a) {
		if err := recover(a); err ! =nil{
			fmt.Printf("Program execution exception: %v\n", err)
		}
	}()

	userFn()
}

func foo(num int)  {
	if num < 10 {
		panic("number is less than 10")}else {
		panic("number is greater than 10")}}func main(a)  {
	try(func(a) {
		foo(9)
	})

	try(func(a) {
		foo(11)})}Copy the code

Go run main.

$go run _test/demo3/test3.go Abnormal program execution: number is less than 10 Abnormal program execution: number is greater than 10Copy the code

As you can see from above, the recover() function completes the function we’ve set up to act as a hook to print out the exception that occurred during program execution.

Add exception handling methods

Catching an exception also requires handling the exception, rather than simply printing the exception to execute. Therefore, it is necessary to add an anonymous method as an exception handling method, which is transformed as follows:

func try(userFn func(a).catchFn func(err interface{})) {
	defer func(a) {
		if err := recover(a); err ! =nil{
			catchFn(err)
		}
	}()

	userFn()
}

...

func main(a)  {
	try(func(a) {
		foo(9)},func(err interface{}) {
		fmt.Printf("Program execution exception: %v\n", err)
	})

	try(func(a) {
		foo(11)},func(err interface{}) {
		fmt.Printf("Program execution exception: %v\n", err)
	})
}
Copy the code

This allows you to pass in custom methods to handle exceptions at will

conclusion

This is just a simple try catch implementation, but there are many drawbacks, such as the lack of support for finally function handling and the simplicity of try catch encapsulation. Here’s the kicker, and then there’s the improvement