Go is a very popular programming language. Due to its efficient concurrent programming and excellent network programming capabilities, it is becoming increasingly popular among developers. In any programming language, error handling is a very important part, which is related to the robustness and reliability of the program. As a modern programming language, Go language naturally has its unique error handling mechanism. In this article, we will explore the error handling mechanism in Go language in depth, including the basic concepts of errors, basic methods of error handling, error packaging and custom error types, etc., to help readers better understand and master the error handling skills of Go language.
1. Basic concepts of error
In any programming language, error handling requires us to first understand the basic concept of errors. In Go, errors are usually an interface type, which is defined as follows:
type error interface { Error() string }
As you can see, the interface only contains an Error method, which returns a string indicating an error message. Therefore, any type can be treated as an error as long as the Error method of the interface is implemented. The standard library in Go provides the errors package, which provides a simple error implementation, as shown below:
package errors func New(text string) error { return &errorString{text} } type errorString struct { s string } func (e *errorString) Error() string { return }
As you can see, the package provides a New function that receives a string parameter and returns an error of the error interface type. The package also defines a private errorString type that implements the Error method of the error interface, indicating a simple string error. When we need to return a simple string error, we can use the New function provided by the package. For example:
import "errors" func someFunc() error { return ("something went wrong") }
2. Error Type
In Go language, error is an interface type, which has only one method Error(), which returns an error message of string type. If a function returns a non-empty error type, it means that an error occurred during the execution of the function.
type error interface { Error() string }
The error type is usually a built-in type error, which we can find in the standard library:
var ( ErrInvalidParam = ("invalid parameter") ErrNotFound = ("not found") ErrInternal = ("internal error") )
In this example, we use the () function to create three error values that will be used for different error cases. When we need to return an error when writing a function, we can return an error value like this.
3. Customize the error type
In Go, we can also define our own error types. Customizing the error type is very useful if we want our error type to contain more information or need to provide some specific behavior.
The custom error type can be of any type as long as it implements the error interface. Here is an example of a custom error type:
type MyError struct { message string code int } func (e *MyError) Error() string { return ("%s (code=%d)", , ) } func processFile(filename string) error { return &MyError{"File not found", 404} } func main() { err := processFile("") ("Error: %s\n", err) }
In the example above, we define a MyError type that contains a message and an error code. We also define an Error() method to meet the requirements of the error interface. Finally, in the processFile() function, we return a new MyError object.
In the main() function, we print the error message. Since the MyError type implements the Error() method, we can print the error object directly without using the () function.
Custom error types are very flexible and can help us better organize our code and handle errors. However, when creating custom error types, we need to follow some best practices:
- The error type should clearly describe the type and cause of the error.
- The error type should match the wrong context. For example, if we are writing a web application, we can define some error types related to HTTP status codes.
- If we need to share certain fields or methods between error types, we can use embedded types.
4. Error handling
In Go, we usually use an if statement to check whether the return value of a function or method is wrong. Here is an example:
package main import ( "fmt" "os" ) func main() { file, err := ("") if err != nil { ("Error: %s", ()) return } defer () // Do file operations here}
In the example above, we use the Open function in the os package to open the file "". If the file cannot be opened, the Open function returns an error value. We use the if statement to check for errors, and if there is an error, print the error message and return it. Otherwise, we use the defer statement to close the file handle.
5. and
In previous versions, to compare whether an error is the same as a specific error, it is necessary to use a string to judge, but this method is not reliable because it is possible that the same error message is represented as a different string in different places, so using a string to judge will be invalid. And the one introduced in Go 1.13and
Functions can solve this problem.
The function can check whether an error is included in the error chain. It accepts two parameters, the first parameter is the error to be checked, and the second parameter is the error to be matched. If the match is successful, the function returns true, otherwise false. The sample code is as follows:
package main import ( "errors" "fmt" ) func main() { err := ("Something went wrong") if (err, ("Something went wrong")) { ("Matched error") } else { ("Did not match error") } }
In the above code, we used a function to check whether err matches ("Something went wrong") . Since their error messages are the same, this function will return true.
In addition, Go 1.13 also introduced another function. Unlike , functions are used to obtain specific types of errors in the error chain. It accepts two parameters. The first parameter is the error to be checked, and the second parameter is a pointer pointing to a variable. The type of this variable is the type of the error we want to obtain. If a matching error is found, the function will assign the error to the variable and return true, otherwise it will return false. The sample code is as follows:
package main import ( "errors" "fmt" ) type myError struct { code int msg string } func (e myError) Error() string { return ("Error with code %d: %s", , ) } func main() { err := myError{code: 404, msg: "Page not found"} var targetErr myError if (err, &targetErr) { ("Matched error: %+v\n", targetErr) } else { ("Did not match error") } }
In the above code, we define a type myError, which implements the Error method. We then create an instance of this type err and define a targetErr variable. Next, we use the function to check whether err matches the type of targetErr. Since they are of the same type, this function returns true and assigns err to targetErr.
6. panic and recover
In Go, panic and recover are two built-in functions for handling errors and exceptions. panic is used to raise a panic, which usually means that a serious error has occurred and the program may not be able to continue execution. recover is used to capture panics to allow programs to resume execution or clean up resources after panics.
6.1 panic function
The panic function can be called at any time, but it is usually used to indicate that a program encounters an unprocessable error. When panic is called, the program stops executing any subsequent code of the current function and starts propagating panic to the top of the call stack. If there is no recover function to capture panic, the program will terminate and print panic's information.
In the following example, we will use the panic function to throw an error:
func checkAge(age int) { if age < 0 { panic("Age cannot be negative!") } ("Age is:", age) } func main() { checkAge(-1) ("Program End") }
In the example above, we define a function called checkAge that accepts an integer parameter age. If age is less than zero, panic will be raised. Otherwise, the function will print the age. In the main function, we call the checkAge function and pass it a negative integer, which will raise a panic. Therefore, ("Program End") will not be executed.
Output:
panic: Age cannot be negative!
goroutine 1 [running]:
(0xffffffffffffffff)
/tmp/sandbox127292069/:5 +0x68
()
/tmp/sandbox127292069/:11 +0x20
Program exited: status 2.
In the above output, we can see information about panic and the source code line of panic. Since the program has stopped running when panic is raised, "Program End" will never be printed.
6.2 recover function
The recover function is used to capture panic and allows the program to resume execution after panic. The recover function must be used in the defer statement to ensure that it is called when panic occurs. If no panic occurs, the recover function returns nil.
In the following example, we will demonstrate how to capture panic using the recover function:
func checkAge(age int) { defer func() { if r := recover(); r != nil { ("Program recovery successfully:", r) } }() if age < 0 { panic("Age cannot be negative!") } ("Age is:", age) } func main() { checkAge(-1) ("Program End") }
Output:
The program recovery is successful: The age cannot be negative!
Program ends
7. Summary
Through this article, we have learned about Go's error handling mechanism, including error types, error handling methods, error chains and custom errors. We also discussed some best practices, such as error handling functions should be called at the end of the function, errors should be handled at the highest level, and errors should not be ignored, etc. In addition, we have also learned the new error handling method in Go 1.13 - is and as functions, which makes error handling more convenient and flexible.
In actual development, error handling is a very important issue. A good error handling mechanism can avoid error transmission, help us diagnose and solve problems faster, and improve the reliability and stability of our code. We need to choose the most suitable error handling method based on actual conditions and always follow best practices.
The above is the detailed content shared by the practice of implementing perfect error handling in Go. For more information about Go error handling, please pay attention to my other related articles!