關閉chanel
傳送者這邊可以傳送一個close(ch)
,接收方收到之後就知道傳送方之後都不會再傳送資訊了。
接收者這邊可以通過一個額外的變數,檢測通道是否已經關閉。類似這樣:v, ok := <- ch
這裡的ok為false就代表我們從一個已經關閉的chanel獲取資料,這個資料是chanel型別對應的零值。
例如:
package main
import (
"fmt"
"time"
)
func main() {
// 子協程:寫10個資料,每寫一次,就阻塞一次,主協程讀取一次,阻塞解除一次
// 主協程:讀取一次資料,阻塞一次,子協程寫一次,阻塞解除一次
ch1 := make(chan int)
go sendData(ch1)
//讀取chanel中的資料,不過由於我們可能不知道傳送方傳送了多少資料, 這裡用死迴圈
for {
time.Sleep(1 * time.Second)
v, ok := <-ch1
if !ok {
fmt.Println("all the data has bean read ", ok)
break
}
fmt.Println("the data read is: ", v, ok)
}
}
func sendData(ch1 chan int) {
// 傳送方: 傳送10條資料
for i := 0; i < 10; i++ {
//把i寫入chanel
ch1 <- i
}
//關閉ch1通道
close(ch1)
}
執行結果是:
the data read is: 0 true
the data read is: 1 true
the data read is: 2 true
the data read is: 3 true
the data read is: 4 true
the data read is: 5 true
the data read is: 6 true
the data read is: 7 true
the data read is: 8 true
the data read is: 9 true
all the data has bean read false
chanel的range迴圈
相對於上面的for 用range能夠省去對ok值的判斷,更加簡潔方便地操作chanel。
下面這個例子中,range的含義就是從通道ch1中讀取資料並且賦值給v:
package main
import (
"fmt"
"time"
)
func main() {
// 子協程:寫10個資料,每寫一次,就阻塞一次,主協程讀取一次,阻塞解除一次
// 主協程:讀取一次資料,阻塞一次,子協程寫一次,阻塞解除一次
ch1 := make(chan int)
go sendData(ch1)
//讀取chanel中的資料,不過由於我們可能不知道傳送方傳送了多少資料, 這裡用死迴圈
for v := range ch1 { //這裡range的含義就是從通道ch1中讀取資料並且賦值給v [v<- ch1]
fmt.Println("reading data: ", v)
}
fmt.Println("main-goroutine completed")
}
func sendData(ch1 chan int) {
// 傳送方: 傳送10條資料
for i := 0; i < 10; i++ {
time.Sleep(1 * time.Second)
//把i寫入chanel
ch1 <- i
}
//關閉ch1通道
close(ch1)
}
執行結果是:
reading data: 0
reading data: 1
reading data: 2
reading data: 3
reading data: 4
reading data: 5
reading data: 6
reading data: 7
reading data: 8
reading data: 9
main-goroutine completed