A little confused about closures

blov · · 825 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hey everyone, I am trying out Go and am confused about something. I am going through the golang book and saw this:</p> <pre><code>func makeEvenGenerator() func() uint { i := uint(0) return func() (ret uint) { ret = i i += 2 return } } func main() { nextEven := makeEvenGenerator() fmt.Println(nextEven()) // 0 fmt.Println(nextEven()) // 2 fmt.Println(nextEven()) // 4 } </code></pre> <p>How does it persist i through those method calls? And also, doesn&#39;t the inner function require a parameter (ret uint)?</p> <p>I apologize if this may be a bit noob-ish. I come from a Java background and it&#39;s pretty different from what I&#39;m used to.</p> <p>Thanks!</p> <hr/>**评论:**<br/><br/>dsymonds: <pre><p>A closure (here, an anonymous function) is called that because it &#34;closes&#34; over the state of all the variables around it. You can imagine that all the vars defined in the same scope (and any outer scopes) are &#34;remembered&#34; by the closure, and are preserved along with that func.</p> <p>In a sense, <em>every</em> function is a closure. It&#39;s just that top-level functions only close over package-level vars, and so are relatively uninteresting in that regard. But non-top-level functions close over those vars <em>and</em> any vars defined inside the function they are created in too, and do that each time they are created.</p></pre>uabassguy: <pre><p>So I can understand too, could you define a var at the package level and increment it within the function? And go remembers the state of the var within the scope of the function?</p> <p>Edit: after reading the example again it appears ret is defined as a uint in the return parameters, is this the de facto standard for doing this kind of persistence or could one do it in the manner I stated earlier?</p></pre>dsymonds: <pre><p>A package-level var incremented in a function:</p> <pre><code>package main import &#34;fmt&#34; var n int func f() { n++ } func main() { f(); fmt.Println(n) f(); fmt.Println(n) f(); fmt.Println(n) } </code></pre> <p>That will print out 1, 2, 3.</p></pre>uabassguy: <pre><p>Awesome! Thanks for clarifying </p></pre>tashbarg: <pre><blockquote> <p>A closure (here, an anonymous function) is called that because it &#34;closes&#34; over the state of all the variables around it. </p> </blockquote> <p>That may depend on an actual implementation or even the school of programming you went through, but in general, a closure only closes over free variables of a function (see, e.g., SICP).</p></pre>z3r0demize: <pre><p>Ah I see. I was mostly confused about how the variable, i, was kept in memory. I am thinking it is because nextEven is a reference to makeEvenGenerator, and as long as nextEven is accessible, then i will not disappear. </p> <p>Is that correct?</p></pre>asaz989: <pre><p>(ret uint) declares a returned variable, not a parameter. The first set of empty parens is for the parameters.</p></pre>FootbaII: <pre><pre><code>return func() (ret uint) { </code></pre> <p>is an anonymous function. It returns a uint (the value of the variable ret). makeEvenGenerator is a closure, meaning a data structure that keeps the anonymous function and any related environment (in this case, the i variable) saved in the variable nextEven. The first time you call nextEven(), i is 0. So, ret becomes 0, and i becomes 2. Next time, i is 2 (remember, the data structure maintains the value of i for this variable nextEven), and so on. Hope this helps.</p></pre>bradfitz: <pre><p>Actually makeEvenGenerator is just a function. It returns a closure. An anonymous function literal can be either just a function literal or closure, depending on whether it closes over outer variables. In this case it does. (Closing over i)</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

825 次点击  
加入收藏 微博
0 回复
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传