A brief analysis of the output result of a Go language code

Source: Internet
Author: User
Tags gopher
This is a creation in Article, where the information may have evolved or changed.

Years later things are really many, all kinds of progress, so a long time not more blog, remorse in ... Jump out today and warm up ^0^!

At noon in the micro-blog private message to see a letter from a gopher, he posted a piece of code, and said the output of the code is puzzled, I hope I can help him analyze. His code is as follows:

//testslicerange.gopackage mainimport (    "fmt"    "time")type field struct {    name string}func (p *field) print() {    fmt.Println(p.name)}func main() {    data1 := []*field{{"one"}, {"two"}, {"three"}}    for _, v := range data1 {        go v.print()    }    data2 := []field{{"four"}, {"five"}, {"six"}}    for _, v := range data2 {        go v.print()    }    time.Sleep(3 * time.Second)}

On Go playground, its output is (in my multicore mac,go 1.10 above the program is slightly different from this, the output of the same item, but the order is different):

onetwothreesixsixsix

Although the Gopher does not clearly state his doubts, what is it? But judging from the above output, he must be asking: Why does the data2 iteration output three "six" instead of four, five, six?

Well, let me analyze it. First of all, I want to do an equivalent transformation of this program, the program after the source code is as follows:

//testslicerange-transform.gopackage mainimport (    "fmt"    "time")type field struct {    name string}func print(p *field) {    fmt.Println(p.name)}func main() {    data1 := []*field{{"one"}, {"two"}, {"three"}}    for _, v := range data1 {        go print(v)    }    data2 := []field{{"four"}, {"five"}, {"six"}}    for _, v := range data2 {        go print(&v)    }    time.Sleep(3 * time.Second)}

Here I change the method:print of the field structure to the normal function print with the field pointer as the first parameter, the transformation is equivalent, Because the method in go is essentially the receiver of method as the normal function of the first parameter, namely:

instance.method(x,y) <=> function(instance, x,y)

Therefore, the results obtained from the above transformed Testslicerange-transform.go are consistent with the Testslicerange.go:

onetwothreesixsixsix

After this transformation, the problem is not enlightened, you can clearly see how to use the Go keyword to start a new goroutine when the parameters are bound:

- 迭代data1时,由于data1中的元素类型是field指针,因此赋值后v就是元素地址, 每次调用print时传入的参数(v)实际上也是各个field元素的地址;- 迭代data2时,由于data2中的元素类型是field(非指针),因此赋值后v是元素的copy,每次传入的&v实际上是v的地址,而不是被copy的元素的地址;

The rest is the "pit" problem that is common to the for range (as detailed in my article on go, 7 things you may not notice), that is, V is only one for the entire for range process, and after the data2 iteration is complete,v is the copy of the element "six" .

Thus, once the various child goroutine that are started are scheduled to execute when the main goroutine executes to sleep, the last three goroutine are printed with the &v printed V
The value "Six" is stored in the The first three child goroutine each pass in the address of the element ("one", "two", "three"), which is printed with the words "one", "two", "three".

So how can the original program be modified to make it output as expected ("one", "one", "three", "four", "five", "six")? Let's change it: just change the receiver type of field method from *field to field.

// testslicerange1.gopackage mainimport (    "fmt"    "time")type field struct {    name string}func (p field) print() {    fmt.Println(p.name)}func main() {    data1 := []*field{{"one"}, {"two"}, {"three"}}    for _, v := range data1 {        go v.print()    }    data2 := []field{{"four"}, {"five"}, {"six"}}    for _, v := range data2 {        go v.print()    }    time.Sleep(3 * time.Second)}

The output of the above program on the Go Playground is:

onetwothreefourfivesix

As for why, can refer to my analytical ideas, self-analysis.

Famous Cloud host service vendor Digitalocean released the latest host plan, the entry-level droplet configuration upgrade to: 1 core CPU, 1G memory, 25G high-speed SSD, price 5$/month. There are friends using Digitalocean needs, you can open this link address: https://m.do.co/c/bff6eed92687 Open your do host road.

My Contact information:

Weibo: https://weibo.com/bigwhite20xx
Public Number: Iamtonybai
Blog: tonybai.com
Github:https://github.com/bigwhite

Appreciated:

Business cooperation: writing, writing, training, online courses, partnerships, business, consulting, advertising cooperation.

2018, Bigwhite. All rights reserved.

Related Posts:

    1. 7 things you might not notice about Go
    2. Go vs. C language Interoperability
    3. A few notable changes in Go 1.4
    4. 3 recently encountered Golang code issues
    5. System signal processing in Go
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.