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

我是 Go 语言的新手,对以下代码感到困惑


package main


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

    }

}

然后它工作正常。输出是斐波那契数列。


有人可以帮我解释一下吗?


温温酱
浏览 213回答 3
3回答

Cats萌萌

这与返回闭包后变量如何封装在闭包中有关。考虑以下示例(播放中的实时代码):func newClosure() func() {&nbsp; &nbsp; i := 0&nbsp; &nbsp; fmt.Println("newClosure with &i=", &i)&nbsp; &nbsp; return func() {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i, &i)&nbsp; &nbsp; &nbsp; &nbsp; i++&nbsp; &nbsp; }}&nbsp; &nbsp;&nbsp;func main() {&nbsp; &nbsp; a := newClosure()&nbsp; &nbsp; a()&nbsp; &nbsp; a()&nbsp; &nbsp; a()&nbsp; &nbsp; b := newClosure()&nbsp; &nbsp; b()&nbsp; &nbsp; a()}运行此代码将产生类似于以下输出的内容。我注释了哪一行来自哪个语句:newClosure with &i= 0xc010000000&nbsp; &nbsp; // a := newClosure()0 0xc010000000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // a()1 0xc010000000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // a()2 0xc010000000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // a()newClosure with &i= 0xc010000008&nbsp; &nbsp; // b := newClosure()0 0xc010000008&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // b()3 0xc010000000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // a()在示例中, 返回的闭包newClosure封装了局部变量i。这对应current于您的代码中的等。你可以看到它a并b 有不同的 实例i,否则调用b()会被打印出来3。您还可以看到i变量具有不同的地址。(该变量已经在堆上,因为 go 没有单独的堆栈内存,所以在闭包中使用它完全没有问题。)因此,通过生成一个新的闭包,您会自动为该闭包创建一个新的上下文,并且局部变量不会在闭包之间共享。这就是为什么在循环中创建一个新的闭包不会让你走得更远的原因。就本例而言,您的代码的等效项是:for i:=0; i < 10; i++ {&nbsp; &nbsp; newClosure()()}并且您已经从输出中看到这是行不通的。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go