例えば:
type name struct {
name string
age int
}
func main() {
c := make(chan name)
c <- name{"sfsaf", 1}
a, b := <- c
close(c)
}
結果:
致命的なエラー:すべてのゴルーチンが眠っています-デッドロック!
チャネルを通じて値を渡したいのですが。私は何をすべきか?
はい、構造体を渡すことができます。しかし、それはあなたのOPの問題ではありません。
受信する準備ができているレシーバーがなかったときに、チャネルで値を送信しました。それがデッドロックの原因です。
チャンネルはreceiver
がsender
を待ってブロックしていることを期待しています。これはGoroutinesで行われます。
したがって、すぐには実行されないgoroutineで送信者をラップします。
_package main
import (
"fmt"
)
type name struct {
name string
age int
}
func main() {
c := make(chan name)
go func() {
c <- name{"sfsaf", 1}
close(c)
}()
for n := range c {
fmt.Println(n)
}
fmt.Println("channel was closed (all done!).")
}
_
遊び場でそれを見てください: https://play.golang.org/p/uaSuCaB4Ms
これは、送信者のゴルーチンがまだ実行されていないため機能します。現在実行中のゴルーチンがブロックされるまでは。
そして、_for n := range c
_ループでブロックされます。これはレシーバーであり、座って値を待っています。 (値を待って座ってブロックするため、forループを使用してチャネル値を反復するのは一般的なパターンです)。
これで、for
ループで値を受信するための待機がブロックされたため、インラインゴールーティングが実行され、チャネルに値を送信します。
さらに、安全な慣行に従い、自分自身とチャネルのclose(c)
を整理して、for
ループまたはselect
ステートメントに、送信される値がないことを通知します。 送信側は常にクローズし、受信側はクローズしません。これは、for
rangeループがforループを終了して残りのコードの実行を続けるために使用するパターンです。
補足として、ポインタではなく、構造体の値を渡すことでうまくいきました。
ポインタを渡した場合、R/Wパニックを防ぐために、オブジェクトの周りにミューテックスロックを実装する必要があります。
メモリを共有して通信するのではなく、通信してメモリを共有してください。
チャネルやゴルーチンの周りにポインタではなく値を渡すことに固執し、メリットを享受してください。