博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
go 创建自定义包_在Go中创建自定义错误
阅读量:2508 次
发布时间:2019-05-11

本文共 10034 字,大约阅读时间需要 33 分钟。

go 创建自定义包

介绍 (Introduction)

Go provides two methods to create errors in the standard library, . When communicating more complicated error information to your users, or to your future self when debugging, sometimes these two mechanisms are not enough to adequately capture and report what has happened. To convey this more complex error information and attain more functionality, we can implement the standard library interface type, .

Go提供了两种在标准库中创建错误的方法: 。 当向用户传达更复杂的错误信息,或在调试时向未来的自我传达信息时,有时这两种机制不足以充分捕获和报告已发生的情况。 为了传达这些更复杂的错误信息并获得更多功能,我们可以实现标准的库接口类型 。

The syntax for this would be as follows:

语法如下:

type error interface {  Error() string}

The package defines error as an interface with a single Error() method that returns an error message as a string. By implementing this method, we can transform any type we define into an error of our own.

程序包使用单个Error()方法将error定义为接口,该方法以字符串形式返回错误消息。 通过实现此方法,我们可以将定义的任何类型转换为我们自己的错误。

Let’s try running the following example to see an implementation of the error interface:

让我们尝试运行以下示例以查看error接口的实现:

package mainimport (    "fmt"    "os")type MyError struct{}func (m *MyError) Error() string {    return "boom"}func sayHello() (string, error) {    return "", &MyError{}}func main() {    s, err := sayHello()    if err != nil {        fmt.Println("unexpected error: err:", err)        os.Exit(1)    }    fmt.Println("The string:", s)}

We’ll see the following output:

我们将看到以下输出:

Output   
unexpected error: err: boomexit status 1

Here we’ve created a new empty struct type, MyError, and defined the Error() method on it. The Error() method returns the string "boom".

在这里,我们创建了一个新的空结构类型MyError ,并在其上定义了Error()方法。 Error()方法返回字符串"boom"

Within main(), we call the function sayHello that returns an empty string and a new instance of MyError. Since sayHello will always return an error, the fmt.Println invocation within the body of the if statement in main() will always execute. We then use fmt.Println to print the short prefix string "unexpected error:" along with the instance of MyError held within the err variable.

main() ,我们调用函数sayHello ,该函数返回一个空字符串和一个MyError的新实例。 由于sayHello将始终返回错误,因此将始终执行main() if语句主体内的fmt.Println调用。 然后,我们使用fmt.Println来打印短前缀字符串"unexpected error:"以及err变量中保存的MyError实例。

Notice that we don’t have to directly call Error(), since the fmt package is able to automatically detect that this is an implementation of error. It calls Error() to get the string "boom" and concatenates it with the prefix string "unexpected error: err:".

注意,我们不必直接调用Error() ,因为fmt包能够自动检测到这是error的实现。 它地调用Error()以获取字符串"boom"并将其与前缀字符串"unexpected error: err:"

在自定义错误中收集详细信息 (Collecting Detailed Information in a Custom Error)

Sometimes a custom error is the cleanest way to capture detailed error information. For example, let’s say we want to capture the status code for errors produced by an HTTP request; run the following program to see an implementation of error that allows us to cleanly capture that information:

有时,自定义错误是捕获详细错误信息的最干净的方法。 例如,假设我们要捕获HTTP请求产生的错误的状态代码。 运行以下程序,查看error的实现,该error使我们能够清晰地捕获该信息:

package mainimport (    "errors"    "fmt"    "os")type RequestError struct {    StatusCode int    Err error}func (r *RequestError) Error() string {    return fmt.Sprintf("status %d: err %v", r.StatusCode, r.Err)}func doRequest() error {    return &RequestError{        StatusCode: 503,        Err:        errors.New("unavailable"),    }}func main() {    err := doRequest()    if err != nil {        fmt.Println(err)        os.Exit(1)    }    fmt.Println("success!")}

We will see the following output:

我们将看到以下输出:

Output   
status 503: err unavailableexit status 1

In this example, we create a new instance of RequestError and provide the status code and an error using the errors.New function from the standard library. We then print this using fmt.Println as in previous examples.

在此示例中,我们创建了RequestError的新实例,并使用标准库中的errors.New函数提供了状态代码和错误。 然后,像前面的示例一样,使用fmt.Println进行打印。

Within the Error() method of RequestError, we use the fmt.Sprintf function to construct a string using the information provided when the error was created.

RequestErrorError()方法中,我们使用fmt.Sprintf函数使用创建错误时提供的信息来构造字符串。

类型断言和自定义错误 (Type Assertions and Custom Errors)

The error interface exposes only one method, but we may need to access the other methods of error implementations to handle an error properly. For example, we may have several custom implementations of error that are temporary and can be retried—denoted by the presence of a Temporary() method.

error接口仅公开一种方法,但我们可能需要访问error实现的其他方法才能正确处理错误。 例如,我们可能有一些error自定义实现,这些实现是临时的并且可以重试-通过Temporary()方法的存在来表示。

Interfaces provide a narrow view into the wider set of methods provided by types, so we must use a type assertion to change the methods that view is displaying, or to remove it entirely.

接口提供了由类型提供的更广泛的方法集的狭窄视图,因此我们必须使用类型断言来更改视图显示的方法,或将其完全删除。

The following example augments the RequestError shown previously to have a Temporary() method which will indicate whether or not callers should retry the request:

下面的示例将前面显示的RequestError扩展为具有Temporary()方法,该方法将指示调用方是否应重试该请求:

package mainimport (    "errors"    "fmt"    "net/http"    "os")type RequestError struct {    StatusCode int    Err error}func (r *RequestError) Error() string {    return r.Err.Error()}func (r *RequestError) Temporary() bool {    return r.StatusCode == http.StatusServiceUnavailable // 503}func doRequest() error {    return &RequestError{        StatusCode: 503,        Err:        errors.New("unavailable"),    }}func main() {    err := doRequest()    if err != nil {        fmt.Println(err)        re, ok := err.(*RequestError)        if ok {            if re.Temporary() {                fmt.Println("This request can be tried again")            } else {                fmt.Println("This request cannot be tried again")            }        }        os.Exit(1)    }    fmt.Println("success!")}

We will see the following output:

我们将看到以下输出:

Output   
unavailableThis request can be tried againexit status 1

Within main(), we call doRequest() which returns an error interface to us. We first print the error message returned by the Error() method. Next, we attempt to expose all methods from RequestError by using the type assertion re, ok := err.(*RequestError). If the type assertion succeeded, we then use the Temporary() method to see if this error is a temporary error. Since the StatusCode set by doRequest() is 503, which matches http.StatusServiceUnavailable, this returns true and causes "This request can be tried again" to be printed. In practice, we would instead make another request rather than printing a message.

main() ,我们调用doRequest() ,它向我们返回一个error接口。 我们首先打印由Error()方法返回的错误消息。 接下来,我们尝试通过使用类型断言re, ok := err.(*RequestError)公开来自RequestError的所有方法。 如果类型声明成功,则使用Temporary()方法查看此错误是否是临时错误。 由于doRequest()设置的StatusCode503 ,与http.StatusServiceUnavailable匹配,因此返回true并导致打印"This request can be tried again" 。 实际上,我们会提出另一个请求,而不是打印一条消息。

包装错误 (Wrapping Errors)

Commonly, an error will be generated from something outside of your program such as: a database, a network connection, etc. The error messages provided from these errors don’t help anyone find the origin of the error. Wrapping errors with extra information at the beginning of an error message would provide some needed context for successful debugging.

通常,错误将从程序外部的某些内容生成,例如:数据库,网络连接等。这些错误提供的错误消息无法帮助任何人找到错误的根源。 在错误消息的开头用额外的信息包装错误将为成功调试提供一些必要的上下文。

The following example demonstrates how we can attach some contextual information to an otherwise cryptic error returned from some other function:

以下示例演示了如何将一些上下文信息附加到其他函数返回的否则为隐秘的error

package mainimport (    "errors"    "fmt")type WrappedError struct {    Context string    Err     error}func (w *WrappedError) Error() string {    return fmt.Sprintf("%s: %v", w.Context, w.Err)}func Wrap(err error, info string) *WrappedError {    return &WrappedError{        Context: info,        Err:     err,    }}func main() {    err := errors.New("boom!")    err = Wrap(err, "main")    fmt.Println(err)}

We will see the following output:

我们将看到以下输出:

Output   
main: boom!

WrappedError is a struct with two fields: a context message as a string, and an error that this WrappedError is providing more information about. When the Error() method is invoked, we again use fmt.Sprintf to print the context message, then the error (fmt.Sprintf knows to implicitly call the Error() method as well).

WrappedError是具有两个字段的结构:作为string的上下文消息,以及此WrappedError提供了更多信息的error 。 调用Error()方法时,我们再次使用fmt.Sprintf打印上下文消息,然后显示error消息( fmt.Sprintf知道也隐式调用Error()方法)。

Within main(), we create an error using errors.New, and then we wrap that error using the Wrap function we defined. This allows us to indicate that this error was generated in "main". Also, since our WrappedError is also an error, we could wrap other WrappedErrors—this would allow us to see a chain to help us track down the source of the error. With a little help from the standard library, we can even embed complete stack traces in our errors.

main() ,我们使用errors.New创建一个错误,然后使用我们定义的Wrap函数包装该错误。 这使我们能够指示此error是在"main"生成的。 另外,由于WrappedError也是一个error ,我们可以包装其他WrappedError -这将使我们看到一个链来帮助我们跟踪错误的来源。 在标准库的一点帮助下,我们甚至可以在错误中嵌入完整的堆栈跟踪。

结论 (Conclusion)

Since the error interface is only a single method, we’ve seen that we have great flexibility in providing different types of errors for different situations. This can encompass everything from communicating multiple pieces of information as part of an error all the way to implementing . While the error handling mechanisms in Go might on the surface seem simplistic, we can achieve quite rich handling using these custom errors to handle both common and uncommon situations.

由于error接口只是一种方法,因此我们已经看到,在为不同情况提供不同类型的错误方面,我们具有极大的灵活性。 这可以涵盖从传递多个信息(作为错误的一部分)一直到实现 。 虽然Go的错误处理机制从表面上看似乎很简单,但是我们可以使用这些自定义错误来处理常见和不常见的情况,从而实现非常丰富的处理。

Go has another mechanism to communicate unexpected behavior, panics. In our next article in the error handling series, we will examine panics—what they are and how to handle them.

Go还有另一种机制来传达意外行为,即恐慌。 在错误处理系列的下一篇文章中,我们将研究恐慌-它们是什么以及如何处理它们。

翻译自:

go 创建自定义包

转载地址:http://fihgb.baihongyu.com/

你可能感兴趣的文章
Springboot集成WebSocket通信全部代码,即扣即用。
查看>>
接口,lambda表达式与内部类
查看>>
【poj1009】 Edge Detection
查看>>
【spoj LCS2】 Longest Common Substring II
查看>>
去掉PowerDesigner生成SQL脚本中字段名带的引号
查看>>
win10操作系统安装oracle11g时出现不满足最低配置的操作INS13001
查看>>
中文乱码问题(页面乱码,eclipse乱码,请求响应乱码)
查看>>
extern使用方法总结!(转)
查看>>
HTTP请求过程详解
查看>>
【C#】wpf中的xmlns命名空间为什么是一个网址,代表了什么意思(转载)
查看>>
你不是迷茫,你是自制力不强
查看>>
【转载】setContentView和inflate区别
查看>>
Bootstrap栅格系统
查看>>
自然语言工程师要求
查看>>
Leetcode 452.用最少数量的箭引爆气球
查看>>
【转】Linux设备驱动之Ioctl控制
查看>>
实例说明>
查看>>
日常理财
查看>>
ng-bind-html在ng-repeat中问题的解决办法
查看>>
制定document.getElementByClassName()
查看>>