The defer of Go language

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed. The defer statement is used to schedule a call to a function. We call this type of function called the defer statement a delay function. Note that the defer statement can only appear inside a function or method. A defer statement always starts with the keyword defer. There must be an expression on the right side of defer, separated by a space "", such as:
Defer FMT. Println ("The finishing touches.")

The expression statement here must represent the invocation of a function or method . Note that since it is an expression statement, some invocation expressions are not allowed to appear here. For example, those invocation expressions for various built-in functions. Because they cannot be called an expression statement. In addition, expression statements that appear in this position cannot be enclosed in parentheses. the execution time of a defer statement is always the first moment that the function that directly contains it returns the process control to its caller, regardless of where the defer statement appears in the function body of the peripheral function. It is divided into the following situations: when the corresponding statements in the function body of the peripheral function are all properly executed, the function does not actually end execution until all the defer statements in the function have been executed. when the return statement in the function body of the peripheral function is executed, the function returns only if all the defer statements in the function have been executed. when there is a run-time panic in the perimeter function, the runtime panic is really spread to the caller of the function only after all the defer statements in the function have been executed. In Summary, the completion of the execution of the perimeter function is deferred due to the execution of the defer statement. because the defer statement has such characteristics, it becomes the first choice to perform the finishing touches such as freeing resources or exception handling. There are two advantages to using the defer statement: first, the final task is always executed, we will not be careless and cause the waste of resources; second, we can place them anywhere in the function body of the peripheral function (usually at the beginning of the function body or immediately after the statement that requested the resource). Instead of just putting it at the end of the function body. This makes the logic of the code clearer, and it becomes clear whether the finishing touches are properly specified. In the defer statement, the function we call can be either a declared named function or an anonymous function that is temporarily written, like this:
Defer func () {        fmt. Println ("The finishing touches.")    } ()


Note that a call expression for an anonymous function consists of a function literal and a pair of parentheses that represent the invocation operation. The advantage of choosing an anonymous function here is that it makes the contents of the function's finishing task more intuitive. However, we can also put a more general finishing task in a named function, and then add it to the defer statement that needs it. Either the named function or the anonymous function to the right of the defer keyword can be called a delay function. Because it is always delayed until the perimeter function is executed before the end of the actual call. whenever the defer statement is executed, the arguments passed to the deferred function are evaluated in the usual way. The following example:
Func begin (FuncName string) string {    fmt. Printf ("Enter function%s.\n", funcName)        return Funcname}func End (FuncName string) string {    fmt. Printf ("Exit function%s.\n", funcName)        return Funcname}func record () {    defer end (Begin ("Record"))        FMT. Println ("in function Record.")}

Outputs: Enter function record. In function record. Exit function record. in the example, the call expression begin ("record") appears as a parameter to the record function. It is evaluated when the defer statement is executed. In other words, the BEGIN function is called when the function body of the record function is executed. However, the End function is called the moment before the end of the record execution of the peripheral function. This is done in addition to avoiding the effect that the parameter values will be changed again before the deferred function is actually called, or the same defer statement may be executed more than once. The following example:
Func printnumbers () {for      I: = 0; i < 5; i++ {               defer FMT. Printf ("%d", i)          }    }

Outputs: 4 3 2) 1 0 The defer statement is executed one time during each iteration of the for statement. In the first iteration, the invocation expression for the deferred function will eventually be the FMT. Printf ("%d", 0). This is because when the defer statement is executed, the parameter i is evaluated first in order to 0, then the value is replaced into the original invocation expression, and the final deferred function call expression is formed. Obviously, the invocation expression at this point is different from the original expression. Therefore, the go language stores the invocation expression after the surrogate parameter value. And so on, the deferred function call expression resulting from several iterations is:
Fmt. Printf ("%d", 1)    FMT. Printf ("%d", 2)    FMT. Printf ("%d", 3)    FMT. Printf ("%d", 4)

The order of evaluation for deferred function call expressions is the exact opposite of the order in which the defer statements where they reside are executed. Each time the go language stores a deferred function call expression that has been placed into a parameter value, it is appended to a list that specifically stores the deferred function call expression for the current perimeter function. This list is always LIFO (last on first out, that is, LIFO). Therefore, the order in which these deferred function call expressions are evaluated is:
Fmt. Printf ("%d", 4)    FMT. Printf ("%d", 3)    FMT. Printf ("%d", 2)    FMT. Printf ("%d", 1)    FMT. Printf ("%d", 0)

Example:
Func appendnumbers (INTs []int) (Result []int) {    result = append (INTs, 1)        FMT. PRINTLN (Result)        defer func () {            result = Append (result, 2)        } ()    result = Append (result, 3)        FMT. PRINTLN (Result)    defer func () {            result = Append (result, 4)        } ()    result = Append (result, 5)        FMT. PRINTLN (Result)    defer func () {            result = Append (result, 6)        } ()        return result}

Outputs: [0 1 3 5 6 4 2] Example:
Func printnumbers () {for    I: = 0; i < 5; i++ {            defer func () {                   fmt. Printf ("%d", I)}            ()}    }

Outputs: 5 5 5) 5 5 The arguments passed to the deferred function when the defer statement is executed are evaluated, but the deferred function call expression is not evaluated at that time. When we put
Fmt. Printf ("%d", i)

instead
Defer func () {            fmt. Printf ("%d", I)} ()

after that, although the variable i is still valid, the value it represents is completely different. During the iteration of the For statement, the defer statement was executed 5 times. However, since we do not pass any arguments to the delay function, the Go language runtime system does not need to evaluate any expression that is a parameter value of the deferred function (because they do not exist at all). When the For statement is executed, a total of 5 deferred function call expressions are stored in their exclusive list. Note that the 5 identical invocation expressions are stored in the exclusive list
Defer func () {            fmt. Printf ("%d", I)} ()

at the end of the execution of the Printnumbers function, the deferred function call expression in that exclusive list is fetched in reverse order and evaluated individually. However, the variable I at this time has been modified in order to 5. Therefore, the evaluation of 5 identical invocation expressions causes 5 to be printed on the standard output. How do I fix this problem? Modify the defer statement to:
Defer func (i int) {            fmt. Printf ("%d", I)            } (i)

Although we still use the anonymous function as the delay function, we add a parameter declaration for this anonymous function and include the variable I as the parameter in the parentheses representing the invocation operation. Thus, when the defer statement is executed, the parameter I passed to the delay function is evaluated. The final deferred function call expression will also resemble the following:
Defer func (i int) {            fmt. Printf ("%d", I)        } (0)

and because the parameter I in the deferred function declaration masks the variable I declared in the for statement, so when the deferred function is executed, the I value used in that print statement is the value of the parameter passed to the delay function .
if the delay function is an anonymous function and there is a named result declaration in the declaration of the perimeter function, the code in the deferred function can access and modify the value of the named result. The following example:
Func modify (n int) (number int) {    fmt. PRINTLN (number)        defer func () {number            + = n        } ()    number++        return}

Modify ( 2 ) with a result of: 3
Although the declaration of a deferred function can contain a result declaration, its returned result value is discarded when it is executed. Therefore, as a rule, we do not add a result declaration to a deferred function when we write it. On the other hand, it is recommended to provide the external values required for the deferred function in the form of a parameter. The following example:
Func modify (n int) (number int) {    fmt. PRINTLN (number)        defer func (plus int) (result int) {             result = n + Plus number                     + = result                     return        } (3) 
  number++        Return}

Modify (2), the result is: 6 we can put the parameter values that we want to pass to the delay function into the parentheses that represent the calling operation, just as you would call a normal function. On the other hand, although we return the result value in the function body of the delay function, it does not produce any effect.
Related Article

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.