Golang: Closure under cyclic (translation)

Source: Internet
Author: User
Tags closure

Original address: Https://github.com/golang/go/wiki/CommonMistakes#wiki-pages-box

Introduction (Introduction)

When the new programmers start using Go or when old Go programmers start using a new concept, there is some common mistakes t Hat many of them make. Here are a non-exhaustive list of some frequent mistakes that show up on the mailing lists and in IRC. Using goroutines on loop iterator variables

When engineers first started using go or go engineers were just beginning to come into contact with a new concept, many of them had similar misconceptions about these concepts. The following is a brief explanation of some common problems in mailing lists and IRC. The iteration variable is used on the go path under the loop.

When iterating on Go, one might attempt to use Goroutines to process data in parallel. For example, the might write something like this, using a closure:

When using the go language to process iterations, someone might try to use the thread to process the data in parallel. For example, you might use closures to write the following code:

for _, val := range values {    go func() {        fmt.Println(val)    }()}

The above for loops might isn't do-what-expect because their Val variable is actually a single variable that takes on th E value of each slice element. Because The closures is all bound to that one variable, there was a very good chance that's when you run this code would see the last element printed for every iteration instead of each value in sequence, because the Goroutines would proba Bly not begin executing until after the loop.

The above code may not run as you expect, because their Val variable is actually a value for each slice element that is worth a single variable. Because these closures are bound to this variable, it is likely that when you execute this code, you will see only the last value in the sequence that is printed, because the association is likely to know that the loop will not be executed until the end of the cycle.

The proper-to-write closure loop is:

The proper way to write a closure loop should be:

for _, val := range values {    go func(val interface{}) {        fmt.Println(val)    }(val)}

By adding Val as a parameter to the closure, Val was evaluated at each iteration and placed on the stack for the Goroutine, So each slice element was available to the goroutine when it was eventually executed.

By adding Val as a parameter to the closure, Val is valued and placed on the stack of the coprocessor, so when the process is finally executed, each slice element is available to the co-process.

It is also important to note that variables declared within the body of a loop was not shared between iterations, and thus Can is used separately in a closure. The following code uses a common index variable i to create separate vals, which results in the expected behavior:

It is also interesting to note that variables declared in the loop body are not shared in each iteration, so they can be used separately in closures. The following code uses a common index variable i to create a separate Val, which produces the expected result.

for i := range valslice {    val := valslice[i]    go func() {        fmt.Println(val)    }()}

Note that without executing this closure as a goroutine, the code runs as expected. The following example prints out the integers between 1 and 10.

Note that the code executes as expected when the closure process is not executed. The following example prints out the numbers 1 through 10.

for i := 1; i <= 10; i++ {    func() {        fmt.Println(i)    }()}

Even though the closures all still close over the same variable (in this case, I), they is executed before the variable C Hanges, resulting in the desired behavior.

Even though these closures are still bound to the same variables (in this case), they are executed before the variable changes, producing the desired result.

Another similar situation that's you could find like following:

Another similar scenario is as follows:

for _, val := range values {    go val.MyMethod()}func (v *val) MyMethod() {        fmt.Println(v)}

The above example also would print last element of values, the reason is same as closure. To fix the issue declare another variable inside the loop.

The example above also prints the last element in values, with the same reason as a closure. To fix this problem, you can declare another variable inside the loop.

for _, val := range values {        newVal := val    go newVal.MyMethod()}func (v *val) MyMethod() {        fmt.Println(v)}
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.