go语言中的递归函数

eth*_*gao 12 go

几天前我开始学习语言.当我试着开始写一些有趣的代码时,我被一种奇怪的行为所困扰.

package main

import "fmt"

func recv(value int) {
    if value < 0 {
        return
    }

    fmt.Println(value)
    go recv(value-1)
}

func main() {
    recv(10)
}
Run Code Online (Sandbox Code Playgroud)

当我运行上面的代码时,只10打印.当我go在打电话之前删除时recv,100打印出来.我相信我在这里滥用常规,但我无法理解为什么它以这种方式失败开始.

Dom*_*nef 16

当main函数返回时,Go不会等待任何仍然存在的goroutine完成,而是退出.

recv 在第一次"迭代"之后将返回main,因为main没有更多的事情要做,程序将终止.

这个问题的一个解决方案是有一个信号表明所有工作都已完成,如下所示:

package main

import "fmt"

func recv(value int, ch chan bool) {
    if value < 0 {
        ch <- true
        return
    }

    fmt.Println(value)
    go recv(value - 1, ch)
}

func main() {
    ch := make(chan bool)
    recv(10, ch)

    <-ch
}
Run Code Online (Sandbox Code Playgroud)

这里,recv将在返回之前发送一个布尔值,并将main在通道上等待该消息.

对于程序的逻辑,使用什么类型或特定值无关紧要.bool而且true只是一个简单的例子.如果你想提高效率,使用a chan struct{}而不是a chan bool将节省额外的字节,因为空结构不使用任何内存.

  • 对于信道通道,通道数据的类型并不重要,可以使用`chan struct {}`.空结构不占用内存,同时仍然允许所需的行为.而布尔值占用一个字节. (4认同)

jim*_*imt 10

A sync.Waitgroup是另一种解决方案,专门用于等待任意数量的goroutine运行它们的过程.

package main

import (
    "fmt"
    "sync"
)

func recv(value int, wg *sync.WaitGroup) {
    if value < 0 {
        return
    }

    fmt.Println(value)

    wg.Add(1) // Add 1 goroutine to the waitgroup.

    go func() {
        recv(value-1, wg)
        wg.Done() // This goroutine is finished.
    }()
}

func main() {
    var wg sync.WaitGroup
    recv(10, &wg)

    // Block until the waitgroup signals
    // all goroutines to be finished.
    wg.Wait()
}
Run Code Online (Sandbox Code Playgroud)