递归函数在Go语言中的实现

huangapple go评论72阅读模式
英文:

recursive function in go language

问题

我几天前开始学习Go语言。当我尝试写一些有趣的代码时,我遇到了一个奇怪的行为。

package main

import "fmt"

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

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

func main() {
    recv(10)
}

当我运行上面的代码时,只打印出10。当我在调用recv之前删除go关键字时,打印出100。我相信我在这里错误地使用了Go协程,但我不明白为什么以这种方式启动一个Go协程会失败。

英文:

I started to learn go language days ago. When I tried to start writing some fun codes, I am stuck by a strange behavior.

package main

import &quot;fmt&quot;

func recv(value int) {
    if value &lt; 0 {
        return
    }

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

func main() {
    recv(10)
}

when I run the above code, only 10 is printed. When I remove the go before the call to recv, 10 to 0 are printed out. I believe I am misusing go routine here, but I can not understand why it failed start a go routine this way.

答案1

得分: 16

当主函数返回时,Go语言不会等待任何仍然存在的goroutine完成,而是直接退出。

recv函数在第一次“迭代”后将返回到主函数,因为主函数没有其他任务要执行,程序将终止。

解决这个问题的一种方法是使用一个信号通道来表示所有工作都已完成,如下所示:

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
}

在这里,recv函数在返回之前会发送一个布尔值,而main函数会在通道上等待该消息。

对于程序的逻辑来说,使用的类型或具体值并不重要。booltrue只是一个简单的示例。如果想要更高效,可以使用chan struct{}而不是chan bool,这样可以节省一个额外的字节,因为空结构体不使用任何内存。

英文:

When the main function returns, Go will not wait for any still existing goroutines to finish but instead just exit.

recv will return to main after the first "iteration" and because main has nothing more to do, the program will terminate.

One solution to this problem is to have a channel that signals that all work is done, like the following:

package main

import &quot;fmt&quot;

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

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

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

	&lt;-ch
}

Here, recv will send a single boolean before returning, and main will wait for that message on the channel.

For the logic of the program, it does not matter what type or specific value you use. bool and true are just a straightforward example. If you want to be more efficient, using a chan struct{} instead of a chan bool will save you an additional byte, since empty structs do not use any memory.

答案2

得分: 10

一个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) // 将1个goroutine添加到waitgroup中。

	go func() {
		recv(value-1, wg)
		wg.Done() // 这个goroutine已经完成。
	}()
}

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

	// 阻塞直到waitgroup发出信号
	// 所有的goroutine都已经完成。
	wg.Wait()
}
英文:

A sync.Waitgroup is another solution and specifically intended for the purpose of waiting for an arbitrary amount of goroutines to run their course.

package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
)

func recv(value int, wg *sync.WaitGroup) {
	if value &lt; 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, &amp;wg)

	// Block until the waitgroup signals
	// all goroutines to be finished.
	wg.Wait()
}

答案3

得分: -2

我这样做了,也起作用。为什么?

package main

import "fmt"

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

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

func main() {
  recv(10)
}
英文:

I did so and also worked. How come?

package main

import &quot;fmt&quot;

func recv(value int) {
    if value &lt; 0 {
      return
    }

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

func main() {
  recv(10)
}

huangapple
  • 本文由 发表于 2012年11月12日 12:11:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/13338281.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定