在 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中文網其他相關文章!