Go のライブラリを読んでいる時に、次のようなメソッドのシグネチャがあって、どういう意味か混乱した。混乱した理由は、channel の矢印の意味合いが理解できていなかったから。
func (client WorkspacesClient) CreateOrUpdate(resourceGroupName string, workspaceName string, parameters Workspace, cancel <-chan struct{}) (<-chan Workspace, <-chan error) {
パラメータにも、戻り値にも、channel
があって、そこに矢印が付いている。これどういう意味?
Channel Direction
これは、チャネルの方向性の記述。
この絵の通りで、チャネルは、ベルトコンベアのようなもので、送る方と、受け取る方がある。製品を組み立てて、ベルトコンベアに載せる方と、受け取る方は例えば、それを箱詰めするとかそんなイメージ。
channel に置ける矢印の記法はそれを明確に表すためのもの。
<-chan
は、送信のみのチャネルです
ic_send_only := make (<-chan int)
chan<-
は、受信のみのチャネルです。
ic_recv_only := make (chan<- int)
なんとなく、ふわっとわかる気もするけど、よーわからんよ。しかも、パラメータと戻り値でもそれがあって、頭はパニックよ。試してみよう。
パラメータの Channel Direction
package main
import (
"fmt"
"time"
)
func receive(c chan<- string, message string) { // channel for send only
c <- message
}
func send(c <-chan string) { // channel for recieve only
fmt.Println(<-c)
}
func main() {
c := make(chan string, 1)
// c <- "hello then"
receive(c, "hello")
fmt.Println(<-c)
c = make(chan string, 1)
c <- "world"
send(c)
}
実行結果
$ go run cmd/spike/main.go
hello
world
ちなみに、試しにこんな感じに変えてみると、 fmt.Println(<-c)
の部分でエラーになってコンパイルできなくなる。
func receive(c chan<- string, message string) { // channel for send
fmt.Println(<-c)
c <- message
}
よし、なんとか、パラメータの方は理解できたぞ。
戻り値の Channel Direction
じゃあ、戻り値はどうよ
func returnChannel() <-chan string {
message := make(chan string, 1)
message <- "hello world again"
return message
}
func returnChannelReverse() chan<- string {
message := make(chan string, 1)
go func(msg chan string) {
fmt.Println(<-msg)
}(message)
return message
}
func main() {
b := returnChannel()
fmt.Println(<-b)
d := returnChannelReverse()
d <- "hello world once upon a time"
time.Sleep(100 * time.Millisecond)
}
戻り値の場合は、基本的に、関数の中で、チャネルを作って、返すけど、それが、送信専用か、受信専用かということになる。<-chan
は、送信のみのチャネル(関数から見て)が戻り値だから、関数を呼んだ方は受信ができる。一方 chan<-
は、受信のみのチャネル(関数から見て)が戻り値なので、関数を呼んだ方は、戻ってきたチャネルに対して送信ができる。という感じ。ちなみに、最後にスリープで待っているのは、ここでスリープを入れないと、 go routine がチャネルから受け付ける前にプログラムが終了するから。
うん。やっとスッキリした。
hello world again
hello world once upon a time