In Go, implementing generators using yield is typically achieved through a combination of goroutines and channels. The generator function creates a goroutine that yields values through a channel, and the consumer function receives those values from the channel in a for-range loop.
According to the Go idioms, the responsibility for closing the channel falls on the generator function. Since the generator has the knowledge of when the iteration is complete, it should close the channel to signal to the consumer that no more values will be received.
In your modified code, you have correctly placed the responsibility for closing the channel on the caller by not closing it in the generator function. However, you should also remove the close() call in the main() function, as it is incorrect to close a channel that is already closed.
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 } } }
When the caller closes the channel, any subsequent attempts to send values to it will result in a runtime panic. This is because the channel is marked as closed, and sending to a closed channel is illegal. However, this panic does not have any negative side effects beyond terminating the goroutine that attempted to send values.
To restrict the channel returned by the library function to receive-only, while still allowing the caller to close it, you can introduce a new type that wraps the channel and exposes only the receive-only channel:
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) }
By wrapping the channel in a new type, you can restrict its accessibility to only receive operations while still allowing the caller to close it through the Close() method of the wrapper type.
The above is the detailed content of How Should Responsibility for Closing Channels in Go Generators Be Handled?. For more information, please follow other related articles on the PHP Chinese website!