Golang try catch
Although I found that there was no error handling mechanism like try catch when using Golang, it seems reasonable to think about golang as an elegant language. Because in Java throws has a keyword in function signature, which aims to make the exception process simpler, but once the expected number of exceptions increases, it is difficult to accurately catch the specific exceptions.
Although golang does not provide the writing method of try catch, the concept of zero value and other designs can be used to process it with panic, which I think is acceptable.
Before we get to the topic, we still need to learn more about panic, recover and error
panic
Golang newbies especially like to treat panic as an exception (I did this too.). Doing so will lead to abuse of panic.
The main usage scenarios of panic:
- A serious error must be withdrawn. The serious judgment standard is that the error cannot be restored, resulting in the program being unable to be executed or continued execution or continued execution, and the predetermined result cannot be obtained. Other scenarios are that the initialization data required for program startup needs to be read in the database. At this time, the database cannot be read or there is no configuration item that cannot be read. At this time, even if the program is executed, it is meaningless. At this time, panic exposes the problem, which is a more preferable way. Non-serious errors, such as the client's illegal request parameters, return an error parameter message prompt, so that the caller can handle the problem by himself, rather than panic by himself.
- Quickly exit error handling. That is, the behavior of try catch that needs to be simulated below. In most cases, error processing should use the mechanism of judging errors, but sometimes the function call stack is very deep, and returning errors layer by layer may require a lot of redundant code to be written. At this time, you can use panic to let the program's control flow jump directly to the top-level recovery for processing. This scenario requires attention and must be recovered in the package. Letting panic pass packages down may lead to more complex problems, so the functions everywhere in the package should not produce panic.
recover
func recover() interface{}
recover is a built-in function to regain control of panic coroutines. Calling recover is only useful if inside the delay function. Calling recover within the delay function can get the error message of panic and stop the panic resumption event (Panicking Sequence), and the program runs back to normal. If recover is called outside of the delay function, the panic resumption event cannot be stopped.
error
The error type built-in in golang is an interface. Custom error types must implement the error interface. In this way, calls can obtain specific error information through Error() without using specific types of related errors.
// The error built-in interface type is the conventional interface for // representing an error condition, with the nil value representing no error. type error interface { Error() string }
Many language limit functions can only have one return value, which is particularly valuable. Golang's multi-return value syntax sugar avoids the inconvenience caused by this method. Error values are generally the last one in the return value list, and other return values are the information that needs to be returned when successful execution. This leads to the following judgment:
if err != nil { // error handling } else { // normal code }
Although this error handling method is a headache to write, it is indeed recommended to use this method in golang style.
Predefined error value
var numIsZero = ("num1 is zero") var numIsNotZero = ("num1 is not zero") func GetInt(num1 int) (int, error) { if num1 == 0 { return num1, numIsZero } else { return num1, numIsNotZero } } //Compare errorfunc ErrEquals() { _, err := GetInt(1) if err == numIsNotZero { } }
Custom error type
HTTP means that there are dozens of error status codes on the client. If the corresponding error value is predefined for each status code, the code will become very cumbersome:
var ErrBadRequest = ("status code 400: bad request") var ErrUnauthorized = ("status code 401: unauthorized")
The best way to do this scenario is to customize an error type and at least implement the Error() method (satisfies the error definition):
type HTTPError struct { Code int Description string } func (h *HTTPError) Error() string { return ("status code %d: %s", , ) }
In this way, when making equivalent values, you need to convert to a specific custom type and then take out the Code field to judge:
func request() error { return &HTTPError{404, "not found"} } func main() { err := request() if err != nil { // an error occured if err.(*HTTPError).Code == 404 { // handle a "not found" error } else { // handle a different error } } }
Use panic and recover to simulate tyr catch. Be cautious!
tyr catch needs to be used with caution, because the biggest difference between panic / recover and try / catch mechanisms lies in the difference in control process. The try/catch mechanism controls the flow to the try code block. When the code block executes to the exception throw point, the control flow jumps out of the try code block, goes to the corresponding catch code block, and then continues to execute. The panic / recover mechanism control flow acts on the entire goroutine call stack. When goroutine is executed to panic, the control flow begins unwind upwards within the call stack of the current goroutine and executes defers for each function. If recover is encountered in defer, the traceback stops. If the defer at the top level of goroutine has not recovered yet, the call stack information will be output at runtime and then exit. Therefore, if you want to use recover to avoid panic causing the process to hang up, recover must be placed in defer. To avoid overly complex code, it is best not to use nested defers, and recover should be directly called in the defer function.
package main import ( "fmt" ) func main() { defer func() { if err := recover(); err != nil { ("error:", err) } }() ("start") panic("Big Error") ("stop") }
Output:
start
error: Big Error
The code in this part is equivalent to the code in the try part once it is panic, it will not be executed, but will jump to the defer part
("start") panic("Big Error") ("stop")
Receive an error and handle the equivalent of catch:
defer func() { if err := recover(); err != nil { ("error:", err) } }()
Note that if you want to catch again, you need to handle exceptions in the order from bottom to top. If you want to catch again, please understand the reason. :
func main() { defer func() { if err := recover(); err != nil { ("error:", err) } }() defer func() { if err := recover(); err != nil { ("Panic again") panic(err) } }() ("start") panic("Big Error") ("stop") } func main() { defer func() { if err := recover(); err != nil { ("error:", err) } }() defer func() { if err := recover(); err != nil { ("Panic again") panic(err) } }() defer func() { if err := recover(); err != nil { ("Panic again") panic(err) } }() defer func() { if err := recover(); err != nil { ("Panic again") panic(err) } }() ("start") panic("Big Error") ("stop") }
Output:
start
Panic again
Panic again
Panic again
error: Big Error
This is the end of this article about the implementation of Golang try catch and error handling. For more related contents of Golang try catch and error handling, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!