如何理解此递归结果

时间:2019-01-13 09:16:08

标签: function go recursion

我在编码时写了一个错误,当我解决问题时,我对代码的输出感到困惑,代码如下:

type (
    Handler func(name string) error
)

func mh(h Handler) Handler {
    return func(name string) error {
        fmt.Printf("return mh,name=%s,h=%x\n", name, h)
        return h(name)
    }
}

func main() {
    var h Handler
    h = func(name string) error {
        fmt.Printf("********************************\n")
        fmt.Printf("before func h=%x\n", h)
        h = mh(h)
        fmt.Printf("after func h=%x\n", h)
        return h(name)
    }
    fmt.Printf("main h=%x\n", h)
    h("main")
}

运行代码,输出为:

main h=486d40
********************************
before func h=486d40
after func h=486c00
return mh,name=main,h=486d40
********************************
before func h=486c00
after func h=486c00
return mh,name=main,h=486c00
return mh,name=main,h=486d40
********************************
before func h=486c00
after func h=486c00
return mh,name=main,h=486c00
return mh,name=main,h=486c00
return mh,name=main,h=486d40
.......

我不了解调用堆栈。我认为输出应为循环“ mh”。

2 个答案:

答案 0 :(得分:0)

罪魁祸首是这个任务:

  h = mh(h) 

它从匿名函数替换了hmainmh返回之前或之后打印的绑定。

如果替换

    h = mh(h)    
    fmt.Printf("after func h=%x\n", h)    
    return h(name)

使用

    return mh(h)(name)

您将获得期望的相互递归

答案 1 :(得分:0)

要理解的关键是这一行:

h = mh(h)

调用h函数。它调用mh()函数,该函数仅返回一个函数值,但也不调用h()。如果将调用返回的函数值,则将调用h()

因此main()函数将函数值存储在h中,然后调用h()

h()打印"before",然后在另一个函数中包装 h,并将结果存储在h中,然后打印{{1 }}。重要的是要知道包装函数(由"after"返回的值)是一个闭包,并且它存储了mh()的原始值,因此将结果分配给h不会影响h位于包装函数中。

因此h通过调用h(现在是包装函数)结束。包装的函数首先打印h,然后调用原始的未包装的"return"

原始的未包装的h再次打印h,然后包装"before"的当前值(这是包装的函数),将其存储在h中,然后打印h

然后调用"after",它现在是2倍包装函数。首先打印h,然后调用保存的"return"值,该值是1次环绕函数。 1次换行功能首先打印h,然后继续进行原始操作,先打印"return",换行"before",现在将进行3次换行,存储它在h中,然后调用h(这是3倍的包装函数值)...

此逻辑继续,存储在h中的函数值将越来越多地被包装,并且包装的函数始终具有比先前的包装函数少一倍的保存值。

随着“迭代”的继续,“包装深度”增加,因此您将看到越来越多的h语句被打印出来(这就是包装的作用)。