为了账号安全,请及时绑定邮箱和手机立即绑定

Go 闭包变量作用域

Go 闭包变量作用域

Go
慕的地6264312 2021-07-05 13:49:41
我正在阅读“CreateSpace An Introduction to Programming in Go 2012”在第 86 页我发现了这个邪恶的魔法func makeEvenGenerator() func() uint {    i := uint(0)    return func() (ret uint) {        ret = i        i += 2        return    }}// here's how it's callednextEven := makeEvenGenerator()fmt.Println(nextEven())fmt.Println(nextEven())fmt.Println(nextEven())1)为什么i不重置?2)正在nextEven()回归,uint或者Println非常聪明,可以处理所有事情?
查看完整描述

3 回答

?
牧羊人nacy

TA贡献1862条经验 获得超7个赞

为了清楚起见,我将为这两个函数指定名称:


func makeEvenGenerator() func() uint { // call this "the factory"

    i := uint(0)


    return func() (ret uint) { // call this "the closure"

        ret = i

        i += 2

        return

    }

}

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


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


f() // prints "f was called"

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


封闭使用命名返回值叫ret。这意味着在闭包中您将隐式声明ret并且在 点处return,ret将返回任何值。


这一行:


ret = i

将分配的电流值i来ref。它不会改变i。但是,这一行:


i += 2

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


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


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())

    }


}


查看完整回答
反对 回复 2021-07-12
?
慕田峪9158850

TA贡献1794条经验 获得超7个赞

1)为什么我不重置?

Go 中的闭包通过引用捕获变量。这意味着内部函数持有i对外部作用域中变量的引用,并且每次调用它都会访问同一个变量。

2) 是 nextEven() 返回并返回 uint 还是 Println 如此聪明以至于它可以处理所有事情?

fmt.Println()(沿fmt.Print()fmt.Fprint()等等)可以工作大多数类型。它以“默认格式”打印其参数。这与fmt.Printf()使用%v动词打印的内容相同。


查看完整回答
反对 回复 2021-07-12
?
繁花不似锦

TA贡献1851条经验 获得超4个赞

闭包中的变量既没有代码段也没有上下文。


查看完整回答
反对 回复 2021-07-12
  • 3 回答
  • 0 关注
  • 222 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信