首页 >后端开发 >Golang >Go 生成器关闭通道的责任应该如何处理?

Go 生成器关闭通道的责任应该如何处理?

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-12-08 11:56:17295浏览

How Should Responsibility for Closing Channels in Go Generators Be Handled?

使用 Yield 的生成器的惯用实现

在 Go 中,使用 Yield 实现生成器通常是通过 goroutine 和通道的组合来实现的。生成器函数创建一个通过通道生成值的 goroutine,消费者函数在 for-range 循环中从通道接收这些值。

关闭通道的职责

根据Go 惯用语中,关闭通道的责任落在了生成器函数上。由于生成器知道迭代何时完成,因此它应该关闭通道,以向消费者发出信号,表明不会再收到任何值。

使用 Caller Deferring Close() 修改代码

在修改后的代码中,您已正确地将关闭通道的责任放在调用者身上,而不是在生成器函数中关闭它。但是,您还应该删除 main() 函数中的 close() 调用,因为关闭已经关闭的通道是不正确的。

package main

import (
    "./lib"
    "fmt"
)

var (
    fruits  = []string{"apple", "banana", "cherry", "durian"}
    banned = "durian"
)

func main() {
    channel := lib.PermutateWithChannel(fruits)
    defer close(channel) // Defer closing the channel

    for myFruits := range channel {
        fmt.Println(myFruits)
        if myFruits[0] == banned {
            break // Break from the loop instead of closing the channel
        }
    }
}

关闭已关闭通道的负面副作用

当调用者关闭通道时,任何后续尝试向其发送值都将导致运行时恐慌。这是因为通道被标记为关闭,发送到关闭的通道是非法的。然而,除了终止尝试发送值的 goroutine 之外,这种恐慌不会产生任何负面影响。

仅接收通道返回类型

限制库函数返回的通道接收-only,同时仍然允许调用者关闭它,您可以引入一种新类型来包装通道并仅公开仅接收通道:

type ReceiveOnlyChannel <-chan []string

func NewReceiveOnlyChannel(channel <-chan []string) *ReceiveOnlyChannel {
    return (*ReceiveOnlyChannel)(&channel)
}

func PermutateWithChannel(strings []string) *ReceiveOnlyChannel {
    // ... (same as before, except it returns ReceiveOnlyChannel)
}

通过将通道包装在新类型中,您可以将其可访问性限制为仅接收操作,同时仍然允许调用者通过包装类型的 Close() 方法关闭它。

以上是Go 生成器关闭通道的责任应该如何处理?的详细内容。更多信息请关注PHP中文网其他相关文章!

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