Go では、Yield を使用したジェネレーターの実装は、通常、ゴルーチンとチャネルの組み合わせによって実現されます。ジェネレーター関数はチャネルを通じて値を生成するゴルーチンを作成し、コンシューマー関数は 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 } } }
呼び出し元がチャネルを閉じると、その後そのチャネルに値を送信しようとすると、実行時パニックが発生します。これは、チャネルが閉鎖済みとしてマークされており、閉鎖されたチャネルへの送信が違法であるためです。ただし、このパニックには、値を送信しようとしたゴルーチンが終了する以上の悪影響はありません。
ライブラリ関数によって返されるチャネルを受信に制限します。 -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) }
チャネルを新しい型でラップすることで、呼び出し元がラッパー型の Close() メソッドを通じてチャネルを閉じることを許可しながら、そのアクセスを操作の受信のみに制限できます。
以上がGo ジェネレーターでチャネルを閉じる責任はどのように扱われるべきですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。