Defer, Panic, and recover[translation]

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.
    • Original: Http://golang.org/doc/articles/defer_panic_recover.html ( by the wall )
    • English: http://zh-golang.appsp0t.com/doc/articles/defer_panic_recover.html

The Go language provides general flow control statements:,,, if for switch goto . It also provides go statements to execute a goroutine. Here we will cover several less common statements: defer , panic , and recover .

A defer called function is temporarily saved to the invocation list. The saved invocation list is executed when the current environment returns. Defer it can be used to simplify code and perform various cleanup operations.

Let's show an example of a file copy: The function needs to open two files and then copy the contents of one of the files to another file:

func CopyFile(dstName, srcName string) (written int64, err error) {    src, err := os.Open(srcName)    if err != nil {        return    }    dst, err := os.Create(dstName)    if err != nil {        return    }    written, err = io.Copy(dst, src)    dst.Close()    src.Close()    return}

The above code can work, but hides a bug. If the second os.Open call fails, it is returned without releasing the source file resource. Although we can add src before the second return statement. Close () call to fix the bug; But when the code becomes complex, similar bugs can be hard to find and fix. Through defer the statements, we can ensure that each file is closed:

func CopyFile(dstName, srcName string) (written int64, err error) {    src, err := os.Open(srcName)    if err != nil {        return    }    defer src.Close()    dst, err := os.Create(dstName)    if err != nil {        return    }    defer dst.Close()    return io.Copy(dst, src)}

Defer language allows us to think about how to close a file when we open it. The file close statement is always executed regardless of how the function returns.

The behavior of the defer statement is simple and predictable. There are three basic principles:

1. When defer invokes a function, the value of each parameter and variable used by the function is also evaluated

In this example, the "i" value of the expression will be defer fmt.Println(i) evaluated at the time. Defer will be printed when the current function returns "0" .

func a() {    i := 0    defer fmt.Println(i)    i++    return}

2. The function called by defer will be executed in a last-in-first-out order when the current function returns.

The following function will output "3210" :

func b() {    for i := 0; i < 4; i++ {        defer fmt.Print(i)    }}

3. A function called by defer can read or modify a named return value after the return statement executes.

In this example, the defer statement will be incremented after the current function returns i 1 . In fact, the function returns 2 :

func c() (i int) {    defer func() { i++ }()    return 1}

With this feature, we can easily modify the error return value of a function. You should see similar examples in the future.

Panicis a built-in function: Stop the current control flow and start panicking . When the F function is called panic , the F function stops executing the subsequent normal statement, but the previous defered function call is still executed normally and then returned to the caller of F. For the caller of the F function, F Behaves like a direct call panic function. The above process will always go along the call stack until the current goroutine return causes the program to crash! The panics can be triggered either by direct invocation panic or by some run-time errors, such as an out-of-bounds access to an array.

RecoverIt is also a built-in function: It is panicking useful for recovering from. Recover and working with it. defer for a normal execution process, the call recover returns nil and has no effect. But if the current goroutine is in a panicking state, call captures panic the parameters at the time of the trigger and reverts to the normal execution process.

The following examples demonstrate panic and defer cooperate with the techniques used:

package mainimport "fmt"func main() {    f()    fmt.Println("Returned normally from f.")}func f() {    defer func() {        if r := recover(); r != nil {            fmt.Println("Recovered in f", r)        }    }()    fmt.Println("Calling g.")    g(0)    fmt.Println("Returned normally from g.")}func g(i int) {    if i > 3 {        fmt.Println("Panicking!")        panic(fmt.Sprintf("%v", i))    }    defer fmt.Println("Defer in g", i)    fmt.Println("Printing in g", i)    g(i + 1)}

The function g has an integer parameter i that i will trigger an exception if the argument is greater than 3 panic , otherwise it will i+1 call itself recursively for the parameter. The function f defers catches the exception by calling in recover , and outputs the argument that triggers the exception (if not nil words). Before looking at the output, the reader can now predict the results of the output.

Output of the program:

Calling g.Printing in g 0Printing in g 1Printing in g 2Printing in g 3Panicking!Defer in g 3Defer in g 2Defer in g 1Defer in g 0Recovered in f 4Returned normally from f.

If we remove a statement from a function, it will f deferred panic not be captured until it spreads to the top of the Goroutine stack, which will eventually cause the program to crash. The following is the result of the modified output:

Calling g.Printing in g 0Printing in g 1Printing in g 2Printing in g 3Panicking!Defer in g 3Defer in g 2Defer in g 1Defer in g 0panic: 4panic PC=0x2a9cd8[stack trace omitted]

A real panic and recover combined use case can refer to the standard library: JSON package. It provides decoding in JSON format, throws an exception when encountering an illegal format input, panic and then panicking spreads to the previous caller stack, which is passed by the caller at the top level. recovercapture panic and error messages (refer to ' Error ' and ' Unmarshal ' in Decode.go).

Go Library implementation habits: Even if pkg used internally panic , but in the export API will be converted to explicit error values.

Another defer scenario to use is release mutex (refer to the example given earlier file.Close() ):

mu.Lock()defer mu.Unlock()

Print headers and footers:

printHeader()defer printFooter()

More.

In summary, the defer statement, whether inclusive or not, panic recover provides an unusual and powerful control flow mechanism. It can be used to simulate some special grammatical structures in some other languages. Enjoy the convenience of defer!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.