<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'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's pretty different from what I'm used to.</p>
<p>Thanks!</p>
<hr/>**评论:**<br/><br/>dsymonds: <pre><p>A closure (here, an anonymous function) is called that because it "closes" 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 "remembered" by the closure, and are preserved along with that func.</p>
<p>In a sense, <em>every</em> function is a closure. It'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 "fmt"
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 "closes" 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
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传