猿问

Golang 在编写函数闭包时会自动将变量分配为参数吗?

这是我引用的代码:


package main


import "fmt"


func adder() func(int) int {

    sum := 0

    return func(x int) int {

        sum += x

        return sum

    }

}


func main() {

    pos, neg := adder(), adder()

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

        fmt.Println(

            pos(i),

            neg(-2*i),

        )

    }

}

以下是运行时的输出:


    0 0

    1 -2

    3 -6

    6 -12

    10 -20

    15 -30

    21 -42

    28 -56

    36 -72

    45 -90

我不明白函数中的语句x是如何分配的?它似乎没有在函数中的任何地方传递。我也不明白这个变量是如何工作的。每次调用该函数并为其赋值时,不应该重置它吗?returnaddersumadder0


湖上湖
浏览 113回答 2
2回答

蓝山帝景

Go 以非常典型/标准的方式处理一流的函数和闭包。在这种情况下,调用adder自身:创建以 valueint命名的对象。sum0返回一个闭包:一个类似函数的东西1,当被调用时,可以访问变量sum。返回的特定类似函数的东西adder(其调用者在普通变量中捕获)是一个带有一个参数的函数。然后你调用它,传递一个参数。这种参数传递没有什么特别之处:它的工作方式与其他地方相同。在类似函数的东西中,使用变量x可以获取调用者传递的值。使用名称sum可以获取捕获的int对象,无论其值是什么。从函数返回后,捕获的内容int仍然被捕获,因此稍后调用相同的类似函数的东西会看到int中的更新sum。通过调用adder两次,您会得到两个略有不同的类似函数的东西:每个都有自己的私有sum. 这两个 privatesum最初都为零。调用您保存了值的类似函数的东西pos可以获得使用其中之一的函数。调用稍微不同的类似函数的东西,你保存了它的值,neg你就可以得到使用另一个函数的函数。1这个“类似函数的东西”和实际的函数之间没有真正的区别,只是这个特定的类似函数的东西没有可以调用它的名称。这或多或少就是拥有一流功能的含义。如果您遇到可读性问题......其原始形式是:func adder() func(int) int {    sum := 0    return func(x int) int {        sum += x        return sum    }}让我们用一些类型名称和其他语法更改来重写它,使代码的核心保持不变。首先,让我们起一个名字,意思是func(int) int:type adderClosure func(int) int然后我们可以用它来重写adder第一行:func adder() adderClosure {    ...}现在让我们在加法器中创建一个局部变量来保存我们要返回的函数。为了明确和冗余,我们可以再次使用这种类型:    var ret adderClosure // not good style: just for illustration现在让我们通过执行以下操作将该变量分配给我们的闭包:    sum := 0    ret = func(x int) int {        sum += x        return sum    }然后我们可以return ret返回闭包。 这是 Go Playground 上的完整代码。

汪汪一只猫

当您分配和时,该sum变量位于两个闭包中。闭包中的是通过添加 1, 2, 3, 4(斐波那契风格)来更新的,而闭包中的是通过在每次循环迭代中减去 2*1, 2*2, 2*3, 2*4 来更新的。posnegsumpossumneg或者,更详细地说: pos := adder()分配给一个函数,该函数具有从0 开始的pos闭包。然后每当您调用该函数时,它都会相应更新。和任何其他类似的作业也是如此。sumsumpossumneg以下是一些类似(更简单)的 JavaScript 代码,可在浏览器控制台中运行:function adder() {  var sum = 0;  return function(i) {    sum += i;    return sum;  }}var pos = adder();console.log( pos(1) ); // add 1 to 0 (1)console.log( pos(2) ); // add 2 to 1 (3)console.log( pos(3) ); // add 3 to 3 (6)console.log( pos(4) ); // add 4 to 6 (10)
随时随地看视频慕课网APP

相关分类

Go
我要回答