How golang's “defer” capture closure's parameter?









up vote
29
down vote

favorite
10












Here is my code (run):



package main

import "fmt"

func main()
var whatever [5]struct

for i := range whatever
fmt.Println(i)
// part 1

for i := range whatever
defer func() fmt.Println(i) ()
// part 2

for i := range whatever
defer func(n int) fmt.Println(n) (i)
// part 3



Output:



0
1
2
3
4
4
3
2
1
0
4
4
4
4
4



Question: What's the difference between part 2 & part 3? Why part 2 output "44444" instead of "43210"?










share|improve this question



























    up vote
    29
    down vote

    favorite
    10












    Here is my code (run):



    package main

    import "fmt"

    func main()
    var whatever [5]struct

    for i := range whatever
    fmt.Println(i)
    // part 1

    for i := range whatever
    defer func() fmt.Println(i) ()
    // part 2

    for i := range whatever
    defer func(n int) fmt.Println(n) (i)
    // part 3



    Output:



    0
    1
    2
    3
    4
    4
    3
    2
    1
    0
    4
    4
    4
    4
    4



    Question: What's the difference between part 2 & part 3? Why part 2 output "44444" instead of "43210"?










    share|improve this question

























      up vote
      29
      down vote

      favorite
      10









      up vote
      29
      down vote

      favorite
      10






      10





      Here is my code (run):



      package main

      import "fmt"

      func main()
      var whatever [5]struct

      for i := range whatever
      fmt.Println(i)
      // part 1

      for i := range whatever
      defer func() fmt.Println(i) ()
      // part 2

      for i := range whatever
      defer func(n int) fmt.Println(n) (i)
      // part 3



      Output:



      0
      1
      2
      3
      4
      4
      3
      2
      1
      0
      4
      4
      4
      4
      4



      Question: What's the difference between part 2 & part 3? Why part 2 output "44444" instead of "43210"?










      share|improve this question















      Here is my code (run):



      package main

      import "fmt"

      func main()
      var whatever [5]struct

      for i := range whatever
      fmt.Println(i)
      // part 1

      for i := range whatever
      defer func() fmt.Println(i) ()
      // part 2

      for i := range whatever
      defer func(n int) fmt.Println(n) (i)
      // part 3



      Output:



      0
      1
      2
      3
      4
      4
      3
      2
      1
      0
      4
      4
      4
      4
      4



      Question: What's the difference between part 2 & part 3? Why part 2 output "44444" instead of "43210"?







      go closures






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 14 '16 at 14:40









      Paweł Szczur

      3,13021928




      3,13021928










      asked Apr 15 '13 at 8:24









      Reck Hou

      2,21262444




      2,21262444






















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          33
          down vote



          accepted










          The 'part 2' closure captures the variable 'i'. When the code in the closure (later) executes, the variable 'i' has the value which it had in the last iteration of the range statement, ie. '4'. Hence the



          4 4 4 4 4


          part of the output.



          The 'part 3' doesn't capture any outer variables in its closure. As the specs say:




          Each time the "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.




          So each of the defered function calls has a different value of the 'n' parameter. It is the value of the 'i' variable in the moment the defer statement was executed. Hence the



          4 3 2 1 0


          part of the output because:




          ... deferred calls are executed in LIFO order immediately before the surrounding function returns ...





          The key point to note is that the 'f()' in 'defer f()' is not executed when the defer statement executes



          but



          the expression 'e' in 'defer f(e)' is evaluated when the defer statement executes.






          share|improve this answer





























            up vote
            0
            down vote













            I would like to address another example in order to improve the understanding of defer mechanish, run this snippet as it is first, then switch order of the statements marked as (A) and (B), and see the result to yourself.



            package main

            import (
            "fmt"
            )

            type Component struct
            val int


            func (c Component) method()
            fmt.Println(c.val)


            func main()
            c := Component
            defer c.method() // statement (A)
            c.val = 2 // statement (B)



            I keep wonderng what are the correct keywords or concepts to apply here. It looks like that the expression c.method is evaluated, thus returning a function binded to the actual state of the component "c" (like taking an snapshot of the component's internal state).
            I guess the answer involves not only defer mechanish also how funtions with value or pointer receiver works. Do note that it also happens that if you change the func named method to be a pointer receiver the defer prints c.val as 2, not as 0.






            share|improve this answer






















            • maybe this is a complex example of something like this play.golang.org/p/yNma_82QIJ9
              – Victor
              Nov 12 at 18:11










            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f16010694%2fhow-golangs-defer-capture-closures-parameter%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            33
            down vote



            accepted










            The 'part 2' closure captures the variable 'i'. When the code in the closure (later) executes, the variable 'i' has the value which it had in the last iteration of the range statement, ie. '4'. Hence the



            4 4 4 4 4


            part of the output.



            The 'part 3' doesn't capture any outer variables in its closure. As the specs say:




            Each time the "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.




            So each of the defered function calls has a different value of the 'n' parameter. It is the value of the 'i' variable in the moment the defer statement was executed. Hence the



            4 3 2 1 0


            part of the output because:




            ... deferred calls are executed in LIFO order immediately before the surrounding function returns ...





            The key point to note is that the 'f()' in 'defer f()' is not executed when the defer statement executes



            but



            the expression 'e' in 'defer f(e)' is evaluated when the defer statement executes.






            share|improve this answer


























              up vote
              33
              down vote



              accepted










              The 'part 2' closure captures the variable 'i'. When the code in the closure (later) executes, the variable 'i' has the value which it had in the last iteration of the range statement, ie. '4'. Hence the



              4 4 4 4 4


              part of the output.



              The 'part 3' doesn't capture any outer variables in its closure. As the specs say:




              Each time the "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.




              So each of the defered function calls has a different value of the 'n' parameter. It is the value of the 'i' variable in the moment the defer statement was executed. Hence the



              4 3 2 1 0


              part of the output because:




              ... deferred calls are executed in LIFO order immediately before the surrounding function returns ...





              The key point to note is that the 'f()' in 'defer f()' is not executed when the defer statement executes



              but



              the expression 'e' in 'defer f(e)' is evaluated when the defer statement executes.






              share|improve this answer
























                up vote
                33
                down vote



                accepted







                up vote
                33
                down vote



                accepted






                The 'part 2' closure captures the variable 'i'. When the code in the closure (later) executes, the variable 'i' has the value which it had in the last iteration of the range statement, ie. '4'. Hence the



                4 4 4 4 4


                part of the output.



                The 'part 3' doesn't capture any outer variables in its closure. As the specs say:




                Each time the "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.




                So each of the defered function calls has a different value of the 'n' parameter. It is the value of the 'i' variable in the moment the defer statement was executed. Hence the



                4 3 2 1 0


                part of the output because:




                ... deferred calls are executed in LIFO order immediately before the surrounding function returns ...





                The key point to note is that the 'f()' in 'defer f()' is not executed when the defer statement executes



                but



                the expression 'e' in 'defer f(e)' is evaluated when the defer statement executes.






                share|improve this answer














                The 'part 2' closure captures the variable 'i'. When the code in the closure (later) executes, the variable 'i' has the value which it had in the last iteration of the range statement, ie. '4'. Hence the



                4 4 4 4 4


                part of the output.



                The 'part 3' doesn't capture any outer variables in its closure. As the specs say:




                Each time the "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.




                So each of the defered function calls has a different value of the 'n' parameter. It is the value of the 'i' variable in the moment the defer statement was executed. Hence the



                4 3 2 1 0


                part of the output because:




                ... deferred calls are executed in LIFO order immediately before the surrounding function returns ...





                The key point to note is that the 'f()' in 'defer f()' is not executed when the defer statement executes



                but



                the expression 'e' in 'defer f(e)' is evaluated when the defer statement executes.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Apr 15 '13 at 9:43

























                answered Apr 15 '13 at 8:32









                zzzz

                51.8k12126112




                51.8k12126112






















                    up vote
                    0
                    down vote













                    I would like to address another example in order to improve the understanding of defer mechanish, run this snippet as it is first, then switch order of the statements marked as (A) and (B), and see the result to yourself.



                    package main

                    import (
                    "fmt"
                    )

                    type Component struct
                    val int


                    func (c Component) method()
                    fmt.Println(c.val)


                    func main()
                    c := Component
                    defer c.method() // statement (A)
                    c.val = 2 // statement (B)



                    I keep wonderng what are the correct keywords or concepts to apply here. It looks like that the expression c.method is evaluated, thus returning a function binded to the actual state of the component "c" (like taking an snapshot of the component's internal state).
                    I guess the answer involves not only defer mechanish also how funtions with value or pointer receiver works. Do note that it also happens that if you change the func named method to be a pointer receiver the defer prints c.val as 2, not as 0.






                    share|improve this answer






















                    • maybe this is a complex example of something like this play.golang.org/p/yNma_82QIJ9
                      – Victor
                      Nov 12 at 18:11














                    up vote
                    0
                    down vote













                    I would like to address another example in order to improve the understanding of defer mechanish, run this snippet as it is first, then switch order of the statements marked as (A) and (B), and see the result to yourself.



                    package main

                    import (
                    "fmt"
                    )

                    type Component struct
                    val int


                    func (c Component) method()
                    fmt.Println(c.val)


                    func main()
                    c := Component
                    defer c.method() // statement (A)
                    c.val = 2 // statement (B)



                    I keep wonderng what are the correct keywords or concepts to apply here. It looks like that the expression c.method is evaluated, thus returning a function binded to the actual state of the component "c" (like taking an snapshot of the component's internal state).
                    I guess the answer involves not only defer mechanish also how funtions with value or pointer receiver works. Do note that it also happens that if you change the func named method to be a pointer receiver the defer prints c.val as 2, not as 0.






                    share|improve this answer






















                    • maybe this is a complex example of something like this play.golang.org/p/yNma_82QIJ9
                      – Victor
                      Nov 12 at 18:11












                    up vote
                    0
                    down vote










                    up vote
                    0
                    down vote









                    I would like to address another example in order to improve the understanding of defer mechanish, run this snippet as it is first, then switch order of the statements marked as (A) and (B), and see the result to yourself.



                    package main

                    import (
                    "fmt"
                    )

                    type Component struct
                    val int


                    func (c Component) method()
                    fmt.Println(c.val)


                    func main()
                    c := Component
                    defer c.method() // statement (A)
                    c.val = 2 // statement (B)



                    I keep wonderng what are the correct keywords or concepts to apply here. It looks like that the expression c.method is evaluated, thus returning a function binded to the actual state of the component "c" (like taking an snapshot of the component's internal state).
                    I guess the answer involves not only defer mechanish also how funtions with value or pointer receiver works. Do note that it also happens that if you change the func named method to be a pointer receiver the defer prints c.val as 2, not as 0.






                    share|improve this answer














                    I would like to address another example in order to improve the understanding of defer mechanish, run this snippet as it is first, then switch order of the statements marked as (A) and (B), and see the result to yourself.



                    package main

                    import (
                    "fmt"
                    )

                    type Component struct
                    val int


                    func (c Component) method()
                    fmt.Println(c.val)


                    func main()
                    c := Component
                    defer c.method() // statement (A)
                    c.val = 2 // statement (B)



                    I keep wonderng what are the correct keywords or concepts to apply here. It looks like that the expression c.method is evaluated, thus returning a function binded to the actual state of the component "c" (like taking an snapshot of the component's internal state).
                    I guess the answer involves not only defer mechanish also how funtions with value or pointer receiver works. Do note that it also happens that if you change the func named method to be a pointer receiver the defer prints c.val as 2, not as 0.







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Nov 12 at 15:48

























                    answered Nov 9 at 19:08









                    Victor

                    2,38222143




                    2,38222143











                    • maybe this is a complex example of something like this play.golang.org/p/yNma_82QIJ9
                      – Victor
                      Nov 12 at 18:11
















                    • maybe this is a complex example of something like this play.golang.org/p/yNma_82QIJ9
                      – Victor
                      Nov 12 at 18:11















                    maybe this is a complex example of something like this play.golang.org/p/yNma_82QIJ9
                    – Victor
                    Nov 12 at 18:11




                    maybe this is a complex example of something like this play.golang.org/p/yNma_82QIJ9
                    – Victor
                    Nov 12 at 18:11

















                     

                    draft saved


                    draft discarded















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f16010694%2fhow-golangs-defer-capture-closures-parameter%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Kleinkühnau

                    Makov (Slowakei)

                    Deutsches Schauspielhaus