dousi7579 2019-08-14 22:24
浏览 53
已采纳

编写函数闭包时,Golang是否会自动将变量分配为参数?

Here is the code I'm referring to:

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),
        )
    }
}

Following is the output when it is run:

    0 0
    1 -2
    3 -6
    6 -12
    10 -20
    15 -30
    21 -42
    28 -56
    36 -72
    45 -90

I don't get how x is being assigned in the return statement in the adder function? It does not seem to be passed anywhere in the function. I also don't get how the sum variable works. Shouldn't it get reset everytime the function adder is called and be assigned the value 0?

  • 写回答

2条回答 默认 最新

  • dongshuang0011 2019-08-14 22:35
    关注

    Go handles first-class functions and closures in a pretty typical / standard way. For some good background on closures in general, see the Wikipedia article. In this case, calling adder itself:

    1. Creates the int object named sum with value 0.
    2. Returns a closure: a function-like thingy1 that, when called, has access to the variable sum.

    The particular function-like thingy that adder returns, which its caller captures in an ordinary variable, is a function that takes one argument. You then call it, passing the one argument. There's nothing special about this argument-passing: it works the same way as it would anywhere else. Inside the function-like thingy, using the variable x gets you the value that the caller passed. Using the name sum gets you the captured int object, whatever its value is. Returning from the function leaves the captured int still captured, so a later call to the same function-like thingy sees the updated int in sum.

    By calling adder twice, you get two slightly-different function-like thingies: each one has its own private sum. Both of these private sums are initially zero. Calling the function-like thingy whose value you've saved in pos gets you the function that uses one of them. Calling the slightly-different function-like thingy whose value you've saved in neg gets you the function that uses the other one.


    1There's no real difference between this "function-like thingy" and an actual function except that this particular function-like thingy doesn't have a name by which you can invoke it. That's more or less what it means to have first-class functions.


    If you're stuck on readability issues...

    The original form of this is:

    func adder() func(int) int {
        sum := 0
        return func(x int) int {
            sum += x
            return sum
        }
    }
    

    Let's rewrite this with a few type names and other syntactic changes that leave the core of the code the same. First, let's make a name that means func(int) int:

    type adderClosure func(int) int
    

    Then we can use that to rewrite adders first line:

    func adder() adderClosure {
        ...
    }
    

    Now let's make a local variable inside adder to hold the function we're going to return. To be explicit and redundant, we can use this type again:

        var ret adderClosure // not good style: just for illustration
    

    Let's now assign that variable to our closure by doing this:

        sum := 0
        ret = func(x int) int {
            sum += x
            return sum
        }
    

    and then we can return ret to return the closure. Here's the complete code on the Go Playground.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试
  • ¥20 问题请教!vue项目关于Nginx配置nonce安全策略的问题
  • ¥15 教务系统账号被盗号如何追溯设备
  • ¥20 delta降尺度方法,未来数据怎么降尺度
  • ¥15 c# 使用NPOI快速将datatable数据导入excel中指定sheet,要求快速高效
  • ¥15 再不同版本的系统上,TCP传输速度不一致