首页 >后端开发 >Golang >如何使用通道在 Go 中惯用地实现递归生成器?

如何使用通道在 Go 中惯用地实现递归生成器?

Susan Sarandon
Susan Sarandon原创
2024-12-05 09:09:13907浏览

How to Idiomatically Implement Recursive Generators in Go Using Channels?

在 Go 中惯用地实现递归函数的生成器

提供的代码演示了使用通道模拟 Python 风格的递归生成器函数。

惯用的实现

按照惯例,Go 中的生成器可以使用以下方式实现goroutine 和通道如下:

  • 使用匿名函数将生成器作为 goroutine 启动: 这允许正确处理关闭通道并响应来自消费者的信号。
  • 让生成器推迟关闭通道:这可以确保通道始终关闭,即使生成器恐慌。
  • 考虑使用信号通道:这允许消费者与生成器进行通信,例如请求堕胎。

关闭通道的责任

通常,生成器函数应该负责关闭通道。这可以确保当生成器完成发送所有值时关闭通道。

修改后的代码

修改后的代码可以惯用地编写为如下:

func permutateWithChannel(channel chan<- []string, strings, prefix []string) {
    defer close(channel)
    length := len(strings)
    if length == 0 {
        channel <- prefix
        return
    }
    newStrings := make([]string, 0, length-1)
    for i, s := range strings {
        newStringsI := append(newStrings, strings[:i]...)
        newStringsI = append(newStringsI, strings[i+1:]...)
        newPrefixI := append(prefix, s)
        go permutateWithChannel(channel, newStringsI, newPrefixI)
    }
}

func PermutateWithChannel(strings []string) chan []string {
    channel := make(chan []string)
    prefix := make([]string, 0, len(strings))
    go permutateWithChannel(channel, strings, prefix)
    return channel
}

调用者

func main() {
    channel := lib.PermutateWithChannel(fruits)
    for myFruits := range channel {
        fmt.Println(myFruits)
        if myFruits[0] == banned {
            return
        }
    }
}

Goroutine 终止和恐慌

消费者关闭通道后关闭通道不会引起恐慌。事实上,尝试向关闭的通道发送值将导致关闭通道错误。

仅接收通道

将库函数限制为仅接收,惯用的方法是使用单独的通道类型来接收值和发送信号。在这种情况下,库函数将具有以下签名:

func PermutateWithChannel(strings []string) (<-chan []string, chan<- struct{})

以上是如何使用通道在 Go 中惯用地实现递归生成器?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn