golang处理错误_处理Go中的错误

golang处理错误

Robust code needs to react correctly to unexpected circumstances like bad user input, faulty network connections, and failing disks. Error handling is the process of identifying when your program is in an unexpected state, and taking steps to record diagnostic information for later debugging.

健壮的代码需要对意外的情况(例如,错误的用户输入,错误的网络连接和磁盘故障)做出正确的React。 错误处理是识别程序何时处于意外状态并采取步骤记录诊断信息以供以后调试的过程。

Unlike other languages that require developers to handle errors with specialized syntax, errors in Go are values with the type error returned from functions like any other value. To handle errors in Go, we must examine these errors that functions could return, decide if an error has occurred, and take proper action to protect data and tell users or operators that the error occurred.

与其他要求开发人员使用特殊语法处理错误的语言不同,Go中的错误是具有从函数返回的类型error值,就像其他值一样。 要处理Go中的错误,我们必须检查函数可以返回的这些错误,确定是否发生了错误,并采取适当的措施保护数据并告知用户或操作员该错误已发生。

产生错误 (Creating Errors)

Before we can handle errors, we need to create some first. The standard library provides two built-in functions to create errors: errors.New and fmt.Errorf. Both of these functions allow you to specify a custom error message that you can later present to your users.

在处理错误之前,我们需要先创建一些错误。 标准库提供了两个内置函数来创建错误: errors.Newfmt.Errorf 。 这两个功能都允许您指定自定义错误消息,以后可以将其呈现给用户。

errors.New takes a single argument—an error message as a string that you can customize to alert your users what went wrong.

errors.New接受一个参数-错误消息作为字符串,您可以自定义该消息以警告用户出了什么问题。

Try running the following example to see an error created by errors.New printed to standard output:

尝试运行以下示例以查看错误所errors.New的错误。将errors.New打印到标准输出中:

package main

import (
    "errors"
    "fmt"
)

func main() {
    err := errors.New("barnacles")
    fmt.Println("Sammy says:", err)
}

   
   
Output
Sammy says: barnacles

We used the errors.New function from the standard library to create a new error message with the string "barnacles" as the error message. We’ve followed convention here by using lowercase for the error message as the Go Programming Language Style Guide suggests.

我们使用标准库中的errors.New函数来创建新的错误消息,并以字符串"barnacles"作为错误消息。 正如Go编程语言样式指南所建议的那样,我们在此处遵循约定,对错误消息使用小写字母。

Finally, we used the fmt.Println function to combine our error message with "Sammy says:".

最后,我们使用fmt.Println函数将错误消息与"Sammy says:"结合在一起。

The fmt.Errorf function allows you to dynamically build an error message. Its first argument is a string containing your error message with placeholder values such as %s for a string and %d for an integer. fmt.Errorf interpolates the arguments that follow this formatting string into those placeholders in order:

使用fmt.Errorf函数可以动态生成错误消息。 它的第一个参数是一个字符串,其中包含错误消息,并带有占位符值,例如%s表示字符串, %d表示整数。 fmt.Errorf将该格式字符串fmt.Errorf的参数按顺序插入到这些占位符中:

package main

import (
    "fmt"
    "time"
)

func main() {
    err := fmt.Errorf("error occurred at: %v", time.Now())
    fmt.Println("An error happened:", err)
}

   
   
Output
An error happened: Error occurred at: 2019-07-11 16:52:42.532621 -0400 EDT m=+0.000137103

We used the fmt.Errorf function to build an error message that would include the current time. The formatting string we provided to fmt.Errorf contains the %v formatting directive that tells fmt.Errorf to use the default formatting for the first argument provided after the formatting string. That argument will be the current time, provided by the time.Now function from the standard library. Similarly to the earlier example, we combine our error message with a short prefix and print the result to standard output using the fmt.Println function.

我们使用了fmt.Errorf函数来生成一条包含当前时间的错误消息。 我们提供给fmt.Errorf的格式字符串包含%v格式指令,该指令指示fmt.Errorf对格式字符串之后提供的第一个参数使用默认格式。 该参数将是标准库中的time.Now函数提供的当前时间。 与前面的示例类似,我们将错误消息与短前缀组合在一起,并使用fmt.Println函数将结果打印到标准输出中。

处理错误 (Handling Errors)

Typically you wouldn’t see an error created like this to be used immediately for no other purpose, as in the previous example. In practice, it’s far more common to create an error and return it from a function when something goes wrong. Callers of that function will then use an if statement to see if the error was present or nil—an uninitialized value.

通常,您不会看到像这样创建的错误可以立即用于其他目的,就像前面的示例一样。 在实践中,更常见的是创建错误并在出现问题时从函数返回错误。 然后,该函数的调用者将使用if语句查看错误是否存在或为nil未初始化的值)。

This next example includes a function that always returns an error. Notice when you run the program that it produces the same output as the previous example even though a function is returning the error this time. Declaring an error in a different location does not change the error’s message.

下一个示例包括一个始终返回错误的函数。 请注意,当您运行该程序时,即使该函数这次返回错误,它也会产生与上一个示例相同的输出。 在其他位置声明错误不会更改错误消息。

package main

import (
    "errors"
    "fmt"
)

func boom() error {
    return errors.New("barnacles")
}

func main() {
    err := boom()

    if err != nil {
        fmt.Println("An error occurred:", err)
        return
    }
    fmt.Println("Anchors away!")
}

   
   
Output
An error occurred: barnacles

Here we define a function called boom() that returns a single error that we construct using errors.New. We then call this function and capture the error with the line err := boom(). Once we assign this error, we check to see if it was present with the if err != nil conditional. Here the conditional will always evaluate to true, since we are always returning an error from boom().

在这里,我们定义了一个名为boom()的函数,该函数返回一个使用errors.New构造的error 。 然后,我们调用此函数并使用err := boom()行捕获错误。 分配了该错误后,我们将检查条件if err != nil存在if err != nil 。 因为我们总是从boom()返回error ,所以条件将始终为true

This won’t always be the case, so it’s good practice to have logic handling cases where an error is not present (nil) and cases where the error is present. When the error is present, we use fmt.Println to print our error along with a prefix as we have done in earlier examples. Finally, we use a return statement to skip the execution of fmt.Println("Anchors away!"), since that should only execute when no error occurred.

情况并非总是如此,因此最好的做法是进行逻辑处理,以解决不存在错误的情况( nil )和存在错误的情况。 当错误出现时,我们使用fmt.Println来打印错误以及带有前缀的fmt.Println ,就像在前面的示例中所做的那样。 最后,我们使用return语句跳过fmt.Println("Anchors away!")执行,因为仅在没有错误发生时才执行。

Note: The if err != nil construction shown in the last example is the workhorse of error handling in the Go programming language. Wherever a function could produce an error, it’s important to use an if statement to check whether one occurred. In this way, idiomatic Go code naturally has its “happy path” logic at the first indent level, and all the “sad path” logic at the second indent level.

注意:最后一个示例中显示的if err != nil构造是Go编程语言中错误处理的主力军。 无论函数在何处产生错误,使用if语句检查是否发生错误都是很重要的。 这样,惯用的Go代码自然在第一个缩进级别具有其“快乐路径”逻辑,而在第二个缩进级别具有所有“悲伤的路径”逻辑。

If statements have an optional assignment clause that can be used to help condense calling a function and handling its errors.

If语句具有可选的赋值子句,可用于帮助压缩压缩调用函数和处理其错误。

Run the next program to see the same output as our earlier example, but this time using a compound if statement to reduce some boilerplate:

运行下一个程序以查看与前面的示例相同的输出,但是这次使用复合if语句来减少一些样板:

package main

import (
    "errors"
    "fmt"
)

func boom() error {
    return errors.New("barnacles")
}

func main() {
    if err := boom(); err != nil {
        fmt.Println("An error occurred:", err)
        return
    }
    fmt.Println("Anchors away!")
}

   
   
Output
An error occurred: barnacles

As before, we have a function, boom(), that always returns an error. We assign the error returned from boom() to err as the first part of the if statement. In the second part of the if statement, following the semicolon, that err variable is then available. We check to see if the error was present and print our error with a short prefix string as we’ve done previously.

和以前一样,我们有一个函数boom() ,该函数始终返回错误。 我们将从boom()返回的错误分配给err作为if语句的第一部分。 在if语句的第二部分中,在分号之后,然后是err变量。 我们检查错误是否存在,并像以前一样用短前缀字符串打印错误。

In this section, we learned how to handle functions that only return an error. These functions are common, but it’s also important to be able to handle errors from functions that can return multiple values.

在本节中,我们学习了如何处理仅返回错误的函数。 这些函数很常见,但是处理能够返回多个值的函数中的错误也很重要。

与值一起返回错误 (Returning Errors Alongside Values)

Functions that return a single error value are often those that effect some stateful change, like inserting rows to a database. It’s also common to write functions that return a value if they completed successfully along with a potential error if that function failed. Go permits functions to return more than one result, which can be used to simultaneously return a value and an error type.

返回单个错误值的函数通常是那些会引起状态变化的函数,例如将行插入数据库。 如果返回的值成功完成,则返回一个值;如果该函数失败,则可能返回错误。 Go允许函数返回多个结果,这些结果可用于同时返回一个值和一个错误类型。

To create a function that returns more than one value, we list the types of each returned value inside parentheses in the signature for the function. For example, a capitalize function that returns a string and an error would be declared using func capitalize(name string) (string, error) {}. The (string, error) part tells the Go compiler that this function will return a string and an error, in that order.

要创建一个返回多个值的函数,我们在函数签名的括号内列出每个返回值的类型。 例如,使用func capitalize(name string) (string, error) {}声明返回stringerrorcapitalize函数。 (string, error)部分告诉Go编译器此函数将按此顺序返回一个string和一个error

Run the following program to see the output from a function that returns both a string and an error:

运行以下程序以查看返回stringerror的函数的输出:

package main

import (
    "errors"
    "fmt"
    "strings"
)

func capitalize(name string) (string, error) {
    if name == "" {
        return "", errors.New("no name provided")
    }
    return strings.ToTitle(name), nil
}

func main() {
    name, err := capitalize("sammy")
    if err != nil {
        fmt.Println("Could not capitalize:", err)
        return
    }

    fmt.Println("Capitalized name:", name)
}

   
   
Output
Capitalized name: SAMMY

We define capitalize() as a function that takes a string (the name to be capitalized) and returns a string and an error value. In main(), we call capitalize() and assign the two values returned from the function to the name and err variables by separating them with commas on the left-hand side of the := operator. After this, we perform our if err != nil check as in earlier examples, printing the error to standard output using fmt.Println if the error was present. If no error was present, we print Capitalized name: SAMMY.

我们将capitalize()定义为一个接受字符串(要大写的名称)并返回字符串和错误值的函数。 在main() ,我们调用capitalize() ,并将函数返回的两个值分配给nameerr变量,方法是在:=运算符的左侧用逗号分隔。 此后,我们像前面的示例一样执行if err != nil检查,如果存在错误,则使用fmt.Println将错误打印到标准输出。 如果没有错误,则打印Capitalized name: SAMMY

Try changing the string "sammy" in name, err := capitalize("sammy") to the empty string ("") and you’ll receive the error Could not capitalize: no name provided instead.

尝试改变字符串"sammy"name, err := capitalize("sammy")为空字符串("")您会收到错误Could not capitalize: no name provided来代替。

The capitalize function will return an error when callers of the function provide an empty string for the name parameter. When the name parameter is not the empty string, capitalize() uses strings.ToTitle to capitalize the name parameter and returns nil for the error value.

当函数的调用者为name参数提供空字符串时, capitalize函数将返回错误。 当name参数不是空字符串时, capitalize()使用strings.ToTitlename参数大写,并为错误值返回nil

There are some subtle conventions that this example follows that is typical of Go code, yet not enforced by the Go compiler. When a function returns multiple values, including an error, convention requests that we return the error as the last item. When returning an error from a function with multiple return values, idiomatic Go code also will set each non-error value to a zero value. Zero values are, for example, an empty string for strings, 0 for integers, an empty struct for struct types, and nil for interface and pointer types, to name a few. We cover zero values in more detail in our tutorial on variables and constants.

此示例遵循一些微妙的约定,这些约定是Go代码的典型,但Go编译器未强制执行。 当一个函数返回多个值(包括错误)时,约定要求我们将error作为最后一项返回。 从具有多个返回值的函数返回error ,惯用的Go代码还将把每个非错误值设置为零值 。 例如,零值是用于字符串的空字符串,用于整数的0 ,用于结构类型的空struct和用于接口和指针类型的nil (仅举几例)。 在有关变量和常量的教程中,我们将更详细地介绍零值。

减少样板 (Reducing boilerplate)

Adhering to these conventions can become tedious in situations where there are many values to return from a function. We can use an anonymous function to help reduce the boilerplate. Anonymous functions are procedures assigned to variables. In contrast to the functions we have defined in earlier examples, they are only available within the functions where you declare them—this makes them perfect to act as short pieces of reusable helper logic.

在从函数返回许多值的情况下,遵守这些约定可能会变得乏味。 我们可以使用匿名函数来帮助减少样板。 匿名函数是分配给变量的过程。 与我们在前面的示例中定义的函数相反,它们仅在声明它们的函数中可用-这使它们非常适合用作可重用的辅助逻辑的简短片段。

The following program modifies the last example to include the length of the name that we’re capitalizing. Since it has three values to return, handling errors could become cumbersome without an anonymous function to assist us:

以下程序修改了最后一个示例,以包含我们要大写的名称的长度。 由于要返回三个值,因此如果没有匿名函数来协助我们,处理错误就会变得很麻烦:

package main

import (
    "errors"
    "fmt"
    "strings"
)

func capitalize(name string) (string, int, error) {
    handle := func(err error) (string, int, error) {
        return "", 0, err
    }

    if name == "" {
        return handle(errors.New("no name provided"))
    }

    return strings.ToTitle(name), len(name), nil
}

func main() {
    name, size, err := capitalize("sammy")
    if err != nil {
        fmt.Println("An error occurred:", err)
    }

    fmt.Printf("Capitalized name: %s, length: %d", name, size)
}

   
   
Output
Capitalized name: SAMMY, length: 5

Within main(), we now capture the three returned arguments from capitalize as name, size, and err, respectively. We then check to see if capitalize returned an error by checking if the err variable was not equal to nil. This is important to do before attempting to use any of the other values returned by capitalize, because the anonymous function, handle, could set those to zero values. Since no error occurred because we provided the string "sammy", we print out the capitalized name and its length.

现在在main() ,我们分别从capitalize捕获的三个返回参数分别为namesizeerr 。 然后,我们通过检查err变量是否不等于nil来检查capitalize返回了error 。 在尝试使用由capitalize返回的任何其他值之前,这样做很重要,因为匿名函数handle可以将这些值设置为零。 由于没有错误,因为我们提供了字符串"sammy" ,所以我们打印出大写的名称及其长度。

Once again, you can try changing "sammy" to the empty string ("") to see the error case printed (An error occurred: no name provided).

再次,您可以尝试将"sammy"更改为空字符串("")以查看打印的错误情况( An error occurred: no name provided )。

Within capitalize, we define the handle variable as an anonymous function. It takes a single error and returns identical values in the same order as the return values of capitalize. handle sets those values to zero values and forwards the error passed as its argument as the final return value. Using this, we can then return any errors encountered in capitalize by using the return statement in front of the call to handle with the error as its parameter.

capitalize ,我们将handle变量定义为匿名函数。 它只有一个错误,并且以与capitalize的返回值相同的顺序返回相同的值。 handle将这些值设置为零值,并将作为其参数传递的error转发为最终返回值。 然后,通过使用调用前面的return语句以error作为参数进行handle ,我们可以返回capitalize遇到的任何错误。

Remember that capitalize must return three values all the time, since that’s how we defined the function. Sometimes we don’t want to deal with all the values that a function could return. Fortunately, we have some flexibility in how we can use these values on the assignment side.

请记住, capitalize必须始终返回三个值,因为这就是我们定义函数的方式。 有时我们不想处理函数可能返回的所有值。 幸运的是,我们在分配方面可以灵活地使用这些值。

处理多次返回功能中的错误 (Handling Errors from Multi-Return Functions)

When a function returns many values, Go requires us to assign each to a variable. In the last example, we do this by providing names for the two values returned from the capitalize function. These names should be separated by commas and appear on the left-hand side of the := operator. The first value returned from capitalize will be assigned to the name variable, and the second value (the error) will be assigned to the variable err. Occasionally, we’re only interested in the error value. You can discard any unwanted values that functions return using the special _ variable name.

当一个函数返回许多值时,Go要求我们将每个值分配给一个变量。 在最后一个示例中,我们通过提供从capitalize函数返回的两个值的名称来实现此目的。 这些名称应以逗号分隔,并出现在:=运算符的左侧。 从capitalize返回的第一个值将分配给name变量,第二个值( error )将分配给变量err 。 有时,我们只对错误值感兴趣。 您可以使用特殊的_变量名来丢弃函数返回的所有不需要的值。

In the following program, we’ve modified our first example involving the capitalize function to produce an error by passing in the empty string (""). Try running this program to see how we’re able to examine just the error by discarding the first returned value with the _ variable:

在下面的程序中,我们修改了涉及capitalize函数的第一个示例,以通过传入空字符串("")产生错误。 尝试运行该程序,看看如何通过使用_变量丢弃第一个返回的值来仅检查错误:

package main

import (
    "errors"
    "fmt"
    "strings"
)

func capitalize(name string) (string, error) {
    if name == "" {
        return "", errors.New("no name provided")
    }
    return strings.ToTitle(name), nil
}

func main() {
    _, err := capitalize("")
    if err != nil {
        fmt.Println("Could not capitalize:", err)
        return
    }
    fmt.Println("Success!")
}

   
   
Output
Could not capitalize: no name provided

Within the main() function this time, we assign the capitalized name (the string returned first) to the underscore variable (_). At the same time, we assign the error returned by capitalize to the err variable. We then check if the error was present in the if err != nil conditional. Since we have hard-coded an empty string as an argument to capitalize in the line _, err := capitalize(""), this conditional will always evaluate to true. This produces the output "Could not capitalize: no name provided" printed by the call to the fmt.Println function within the body of the if statement. The return after this will skip the fmt.Println("Success!").

这次在main()函数中,我们将大写名称(首先返回的string )分配给下划线变量( _ )。 同时,我们将capitalize返回的error分配给err变量。 然后,我们检查if if err != nil存在if err != nil 。 因为我们有硬编码一个空字符串作为参数,以capitalize该行_, err := capitalize("")这将有条件始终评估为true 。 这将生成对if语句主体中的fmt.Println函数的调用打印的输出"Could not capitalize: no name provided" 。 此后的return将跳过fmt.Println("Success!")

结论 (Conclusion)

We’ve seen many ways to create errors using the standard library and how to build functions that return errors in an idiomatic way. In this tutorial, we’ve managed to successfully create various errors using the standard library errors.New and fmt.Errorf functions. In future tutorials, we’ll look at how to create our own custom error types to convey richer information to users.

我们已经看到了许多使用标准库创建错误的方法,以及如何构建以惯用方式返回错误的函数。 在本教程中,我们设法使用标准库errors.Newfmt.Errorf函数成功创建了各种错误。 在以后的教程中,我们将研究如何创建自己的自定义错误类型以向用户传达更丰富的信息。

翻译自: https://www.digitalocean.com/community/tutorials/handling-errors-in-go

golang处理错误

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值