In Go language, error is an interface type. The error interface type is a standard mode for error handling. If the function returns an error, the return value type list must contain error; the error processing process is similar to the error code in C language, and can be returned layer by layer until it is processed. The error interface type is defined as an Error() string containing only one method; all types that implement this interface can be used as an error type.
The operating environment of this tutorial: Windows 7 system, GO version 1.18, Dell G3 computer.
Go errors refer to artificial or automatic feedback mechanisms caused by situations that are inconsistent with the design process during program execution. Some errors are deliberately designed, and error handling is added, or feedback is given to the user to wait for processing. For example, if the divisor is checked to be 0, an error will be reported, so that the user can recognize the problem of his own input. Another example is to crawl the specified page information. The code encountered a network disconnection; other errors were BUGs caused by poor programming, such as array access subscripts out of bounds, null pointer operations leading to crashes, etc. Well-designed error handling for various situations is one of the signs of mature code, and it also requires accumulated experience or careful design.
The error type of Go language
Go errors are represented by error, which is an interface type and is usually declared together with the return value.
Error handling is an important part of every programming language. Usually, there are two types of exceptions and errors encountered in development, and Go language is no exception.
In C language, errors are expressed by returning information such as -1 or NULL, but for users, if they do not check the corresponding API documentation, they will not know what this return value actually means. Meaning, for example, returning 0 is success or failure?
In response to this situation, the error interface type is introduced in the Go language as a standard mode for error handling. If the function returns an error, the return value type list must contain error. The error processing process is similar to the error code in C language and can be returned layer by layer until it is processed.
The error interface type is defined as an Error() string containing only one method. All types that implement this interface can be treated as an error type. The Error() method gives a description of the error. This means that all data types can be equipped with error types.
//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 }
//DNSError represents a DNS lookup error. type DNSError struct { Err string // description of the error Name string // name looked for Server string // server used IsTimeout bool // if true, timed out; not all timeouts set this IsTemporary bool // if true, error is temporary; not all errors set this; added in Go 1.6 } func (e *DNSError) Error() string func (e *DNSError) Temporary() bool //Temporary reports whether the DNS error is known to be temporary. This is not always known; a DNS lookup may fail due to a temporary error and return a DNSError for which Temporary returns false. func (e *DNSError) Timeout() bool //Timeout reports whether the DNS lookup is known to have timed out. This is not always known; a DNS lookup may fail due to a timeout and return a DNSError for which Timeout returns false.
Look specifically at *DNSError to understand the definition of an error type. *DNSError contains 5 field structures. Err describes the error text, Name is the domain name of the query, used by the Server server, and IsTimeout and IsTemporary are two Boolean quantities indicating the cause of the error. Use the following examples to understand this in detail.
func main() { name := "www.ilydsssss.com" addr, err := net.LookupHost(name) if errS, ok := err.(*net.DNSError); ok { fmt.Printf("%+v\n", *errS) fmt.Println(err) } else { fmt.Println(name, addr) } } /* result for ------www.ilydsssss.com------------ {Err:no such host Name:www.ilydsssss.com Server: IsTimeout:false IsTemporary:false} lookup www.ilydsssss.com: no such host ------------ www.iloveyou.com------------ {Err:getaddrinfow: This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server. Name:www.iloveyou.com Server: IsTimeout:false IsTemporary:false} lookup www.iloveyou.com: getaddrinfow: This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server. 传说中的发送DNS,没有返回的结果,原因你懂的, 这个是什么站点,noidea ----------- www.baidu.com ------------ www.baidu.com [180.97.33.108 180.97.33.107]
In the above use case, if the query fails (that is, the pointer is not nil), a type assertion is made. If it is a *net.DNSError pointer, the structure field is printed and an error is output; otherwise, the domain name and address. It can be seen that among the two types of errors defined, the above query did not return any one, but it was indeed an error.
At the same time, you can also guess that the definition of func (e *DNSError) Error() string is return "look " e.Name e.Err.
Creation of error
Go’s internal error feedback is defined in this way. How to define a new error type.
Define the structure and implement the error interface
Create a new structure and model the above DNSError to create an error that needs to be saved The structure can be implemented by implementing the error interface at the same time.
error.New() function
package errors // New returns an error that formats as the given text. func New(text string) error { return &errorString{text} } // errorString is a trivial implementation of error. type errorString struct { s string } func (e *errorString) Error() string { return e.s }
errorString is a structure type that contains only one string , and implements the error interface. The New() function just initializes errorString with a string describing the error and returns the structure address. This allows a simple error type to be called directly at any time without creating a structure and Implement the interface and use method 1 if necessary.
Use fmt.Errorf() to return error interface
fmt.Errorf() function signature: func Errorf( format string, a ...interface{}) error, which uses a formatted string and returns a signature using the above method. Do you still remember that func Sprintf(format string, a ...interface{}) string, fmt.Errorf() implementation only returns error.New(fmt.Sprintf(format string, a ...interface{}))
Error handling
当写一个库时,如果发生一个错误,一种方式就是按照上述所说,抛出一个错误,由上层或用户去决断如何处理,是退出还是提示修改;另一种方式就是抛出 panic 来终止程序,除非遇到特别严重的错误,什么叫严重呢?就是程序已经没有执行的必要了,莫不如抛出错误,直接退出。有两种情况可以考虑使用 panic: 1. 发生了一个不能恢复的错误,此时程序不能继续运行。2. 存在一个编程上的错误。
当程序由 panic 引发终止时,可以使用 recover 重新获取该程序控制权。panic 和 recover 与其他语言中的 try-catch-finally 语句类似,只不过一般我们很少使用 panic 和 recover。
内建函数 panic 的签名为:func panic(interface{}),此处接口为空接口,也可以理解为任意数据类型都可以输入,输入什么,则提示什么。
func div(x, y int) float64 { defer fmt.Println("DIV ......") if y == 0 { panic(fmt.Sprintf("%d / %d, 除数为零, 无法计算", x, y)) } return float64(x) / float64(y) } fmt.Println(div(3, 0)) /* result panic: 3 / 0, 除数为零 goroutine 1 [running]: main.div(0x3, 0x0, 0x2) error.go:10 +0x148 main.main() error.go:25 +0x15a exit status 2 */
从上述例子可以看到,当函数发生 panic 时,它会终止运行,在执行完所有的延迟函数后,程序控制返回到该函数的调用方。这样的过程会一直持续下去,直到当前协程的所有函数都返回退出,然后程序会打印出 panic 信息,接着打印出堆栈跟踪,最后程序终止。
recover 是一个内建函数,用于重新获得 panic 协程的控制。recover 函数的标签如下所示:func recover() interface{}。需要注意的是:只有在延迟函数的内部,调用 recover 才有用。在延迟函数内调用 recover,可以取到 panic 的错误信息,并且停止 panic 续发事件,程序运行恢复正常。如果在延迟函数的外部调用 recover,就不能停止 panic 续发事件。
例如:
import ( "runtime/debug" ) func recoverFdiv() { if r := recover(); r != nil { fmt.Println("来自 DIV 的恢复, 除数为零,下面是出错log记录") debug.PrintStack() } } func div(x, y int) float64 { defer recoverFdiv() if y == 0 { panic(fmt.Sprintf("%d / %d, 除数为零, 无法计算", x, y)) } return float64(x) / float64(y) } fmt.Println(div(3, 0)) /* result 来自 DIV 的恢复, 除数为零,下面是出错log记录 goroutine 1 [running]: runtime/debug.Stack(0xc000072008, 0xc00006fd68, 0x1) runtime/debug/stack.go:24 +0xae runtime/debug.PrintStack() runtime/debug/stack.go:16 +0x29 main.recoverFdiv() D:/ZHY-L/OneDrive/文档/开发/goblog/myerror.go:12 +0x89 panic(0x4b9620, 0xc000030040) runtime/panic.go:513 +0x1c7 main.div(0x3, 0x0, 0x0) error.go:19 +0x186 main.main() error.go:34 +0x15a 0 */
如上所示,调用延迟函数 recoverFdiv(),它使用了 recover() 来停止 panic 续发事件,主函数还是继续执行了。同时,利用debug.PrintStack() 打印了 panic 记录,这样在保证程序继续执行的同时,也留下了调试宝贵的记录。
同理,Go 内置的运行时错误(如数组越界)也会导致 panic。这等价于调用了内置函数 panic,其参数由接口类型 runtime.Error 给出。runtime.Error 接口的定义如下:
type Error interface { error // RuntimeError is a no-op function but // serves to distinguish types that are run time // errors from ordinary errors: a type is a // run time error if it has a RuntimeError method. RuntimeError() }
The above is the detailed content of What is the error type in Go language?. For more information, please follow other related articles on the PHP Chinese website!