在 Go 中,使用 Yield 实现生成器通常是通过 goroutine 和通道的组合来实现的。生成器函数创建一个通过通道生成值的 goroutine,消费者函数在 for-range 循环中从通道接收这些值。
根据Go 惯用语中,关闭通道的责任落在了生成器函数上。由于生成器知道迭代何时完成,因此它应该关闭通道,以向消费者发出信号,表明不会再收到任何值。
在修改后的代码中,您已正确地将关闭通道的责任放在调用者身上,而不是在生成器函数中关闭它。但是,您还应该删除 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中文网其他相关文章!