goroutine を指定した関数は、戻り値を返すことができなくなります。そこでチャネル(channel、道筋)という機能を使って、goroutine を指定した関数からもデータを受け取れるようにします。
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("started")
result := make(chan int)
go times(44, result)
go plus (44)
fmt.Println(<- result)
time.Sleep(time.Second * 2)
fmt.Println("calculation is complete")
time.Sleep(time.Second * 2)
fmt.Println("finished")
}
func times(i int, result chan int) {
time.Sleep(time.Second * 4)
fmt.Printf("%d * %d = ", i, i)
result <- i * i
}
func plus(i int) {
time.Sleep(time.Second * 2)
fmt.Printf("%d + %d = %4d\n", i, i, i+i)
}
started
44 + 44 = 88
44 * 44 = 1936
calculation is complete
finished
result := make(chan int)
チャネルは参照型として取り扱います。make(chan 型) と記述することによって、チャネルのポインターを宣言できます。
go times(44, result)
go plus (44)
goroutine を指定した関数にも、引数は渡すことはできます。チャネルも引数として関数に渡します。
fmt.Println(<- result)
チャネルにはデータの受け渡しをすることができます。チャネルからデータを受け取るには、<- チャネル名と記述します。ここで注意しなければいけないことは、関数側でチャネルにデータが渡されるまでは、ここで処理がストップするということです。
time.Sleep(time.Second * 2)
fmt.Println("calculation is complete")
スリープ時間を 2 秒に設定しています。しかし、チャネルにデータが入るまでは処理がストップしていますので、チャネルにデータが入るまでは、この処理が実行されることはありません。仮に、ここにスリープ時間を設定しなくても、処理が先に進んで main 関数が先に終わることはありません。
func times(i int, result chan int) {
チャネルを引数として受け取るには、変数名と型の間に chan と記述します。
result <- i * i
チャネルにデータを渡すには、チャネル名 <- データと記述します。関数側でチャネルにデータを渡すまでは、データの受け取り側は処理をストップしています。