Go关闭变量范围 [英] Go closure variable scope

查看:165
本文介绍了Go关闭变量范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读CreateSpace 2012年编程入门



和第86页我发现了这个邪恶的魔法

  func makeEvenGenerator()func()uint {
i:= uint(0)

return func {
ret = i
i + = 2
return
}
}

//这里叫做
nextEven: = makeEvenGenerator()
fmt.Println(nextEven())
fmt.Println(nextEven())
fmt.Println(nextEven())

1)为什么 i 不会重置?
2)是 nextEven()返回和 uint 或者是 Println 这么聪明,它可以处理一切?

解决方案

为了清楚起见,这两个函数:

  func makeEvenGenerator()func()uint {//将这个工厂命名为
i: = uint(0)

return func()(ret uint){//称为闭包
ret = i
i + = 2
return
}
}

工厂返回闭包–函数是Go中的头等公民,即它们可以是右手表达式,例如:

  f:= func fmt.Println(f called called); } 

f()// printsf被调用

代码,闭包覆盖了工厂的上下文,这被称为词法范围。这就是为什么变量 i 在闭包中可用,而不是作为副本,而是作为 i 本身的引用。



闭包使用名为 ret 命名的返回值。这意味着在闭包内你将隐式声明 ret ,在 return 的时候, ret 将被退回。



此行:

  ret = i 

将分配当前值 i ref 。它不会更改 i 。但是,此行:

  i + = 2 

将会在下一次调用闭包时更改 i 的值。






这里你会发现一个小例子写在一起为你。这不是非常有用,但说明了封闭的范围,目的和使用在我看来很好:

  package main 

importfmt

func makeIterator(s [] string)func()func()string {
i:= 0
return func() string {
if i == len(s){
return nil
}
j:= i
i ++
return func()string {
return s [j]
}
}
}

func main(){

i:= makeIterator {hello,world,this,is,dog})

for c:= i c!= nil; c = i(){
fmt.Println(c())
}

}

I'm reading 'CreateSpace An Introduction to Programming in Go 2012'

and on page 86 I found this evil magic

func makeEvenGenerator() func() uint {
    i := uint(0)

    return func() (ret uint) {
        ret = i
        i += 2
        return
    }
}

// here's how it's called
nextEven := makeEvenGenerator()
fmt.Println(nextEven())
fmt.Println(nextEven())
fmt.Println(nextEven())

1) Why is i not resetting ? 2) is nextEven() returning and uint or is Println so smart that it can work with everything ?

解决方案

For the sake of clarity, I'll assign names to both functions:

func makeEvenGenerator() func() uint { // call this "the factory"
    i := uint(0)

    return func() (ret uint) { // call this "the closure"
        ret = i
        i += 2
        return
    }
}

The factory returns the closure – functions are first class citizens in Go i.e. they can be right-hand expressions, for example:

f := func() { fmt.Println("f was called"); }

f() // prints "f was called"

In your code, the closure wraps over the context of the factory, this is called lexical scoping. This is why the variable i is available inside the closure, not as a copy but as a reference to i itself.

The closure uses a named return value called ret. What this means is that inside the closure you'll have implicitly declared ret and at the point of return, whatever value ret has will be returned.

This line:

ret = i

will assign the current value of i to ref. It will not change i. However, this line:

i += 2

will change the value of i for the next time the closure is called.


Here you'll find a little closure example I wrote together for you. It's not extremely useful but illustrates the scope, purpose and use of closures pretty well in my opinion:

package main

import "fmt"

func makeIterator(s []string) func() func() string {
    i := 0
    return func() func() string {
        if i == len(s) {
            return nil
        }
        j := i
        i++
        return func() string {
            return s[j]
        }
    }
}

func main() {

    i := makeIterator([]string{"hello", "world", "this", "is", "dog"})

    for c := i(); c != nil; c = i() {
        fmt.Println(c())
    }

}

这篇关于Go关闭变量范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆