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

直接调用函数和使用指针的不同行为

直接调用函数和使用指针的不同行为

Go
温温酱 2021-06-30 14:03:54
我是 Go 语言的新手,对以下代码感到困惑package mainimport "fmt"// fibonacci is a function that returns// a function that returns an int.func fibonacci() func() int {    previous := 0    current := 1    return func () int{        current = current+previous        previous = current-previous        return current    }}func main() {    f := fibonacci    for i := 0; i < 10; i++ {        fmt.Println(f()())    }}这段代码应该打印出斐波那契数列(前 10 个),但只打印出 10 次 1。但是如果我将代码更改为:func main() {    f := fibonacci()    for i := 0; i < 10; i++ {        fmt.Println(f())    }}然后它工作正常。输出是斐波那契数列。有人可以帮我解释一下吗?
查看完整描述

3 回答

?
Cats萌萌

TA贡献1805条经验 获得超9个赞

这与返回闭包后变量如何封装在闭包中有关。考虑以下示例(播放中的实时代码):


func newClosure() func() {

    i := 0

    fmt.Println("newClosure with &i=", &i)

    return func() {

        fmt.Println(i, &i)

        i++

    }

}    


func main() {

    a := newClosure()

    a()

    a()

    a()

    b := newClosure()

    b()

    a()

}

运行此代码将产生类似于以下输出的内容。我注释了哪一行来自哪个语句:


newClosure with &i= 0xc010000000    // a := newClosure()

0 0xc010000000                      // a()

1 0xc010000000                      // a()

2 0xc010000000                      // a()

newClosure with &i= 0xc010000008    // b := newClosure()

0 0xc010000008                      // b()

3 0xc010000000                      // a()

在示例中, 返回的闭包newClosure封装了局部变量i。这对应current于您的代码中的等。你可以看到它a并b 有不同的 实例i,否则调用b()会被打印出来3。您还可以看到i变量具有不同的地址。(该变量已经在堆上,因为 go 没有单独的堆栈内存,所以在闭包中使用它完全没有问题。)


因此,通过生成一个新的闭包,您会自动为该闭包创建一个新的上下文,并且局部变量不会在闭包之间共享。这就是为什么在循环中创建一个新的闭包不会让你走得更远的原因。


就本例而言,您的代码的等效项是:


for i:=0; i < 10; i++ {

    newClosure()()

}

并且您已经从输出中看到这是行不通的。


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

添加回答

举报

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