轉載請註明出處:
在Go語言中,select語句用於處理多個通道的並行操作。它類似於switch語句,但是select語句用於通訊操作,而不是條件判斷。select語句會同時監聽多個通道的操作,並選擇其中一個可用的通道進行操作。 select語句的語法如下:
select { case <-channel1: // 執行channel1的操作 case data := <-channel2: // 執行channel2的操作,同時將通道中的資料賦值給data變數 case channel3 <- data: // 將data寫入channel3 default: // 當沒有任何通道操作時執行default語句 }
select
語句中可以包含多個case
子句,每個case
子句表示一個通道操作。<-
符號用於從通道中讀取資料,channel <- data
如果有多個通道都可以操作,則隨機選擇一個進行操作。
如果沒有任何通道可以操作,則會執行default
語句(如果有)。
如果沒有default
語句,則select
語句會阻塞,直到至少有一個通道可以操作。
下面是一個使用select
語句的範例:
package main import ( "fmt" "time" ) func main() { ch1 := make(chan int) ch2 := make(chan int) go func() { time.Sleep(time.Second) ch1 <- 1 fmt.Println("ch1 ending") }() go func() { time.Sleep(2 * time.Second) ch2 <- 2 fmt.Println("ch2 ending") }() select { case data := <-ch1: fmt.Println("收到ch1的資料:", data) case data := <-ch2: fmt.Println("收到ch2的資料:", data) case <-time.After(100 * time.Second): fmt.Println("超時:沒有接收到任何資料") } }
在上面的例子中,我們建立了兩個通道ch1
和ch2
,並分別在不同的goroutine中向它們傳送資料。然後使用select
語句監聽這兩個通道的操作,當其中一個通道可用時,就會執行對應的case
語句。
在這個例子中,由於ch1
的資料傳送操作會在1秒後執行,而ch2
的資料傳送操作會在2秒後執行,因此select
語句會等待1秒後,執行ch1
的case
語句,輸出"收到ch1的資料: 1"。如果我們將ch1
的傳送操作改為在2秒後執行,那麼select
語句將會等待2秒後,執行ch2
的case
語句,輸出"收到ch2的資料: 2"。
需要注意的是,select
如果希望持續監聽多個通道的操作,可以將select
語句放在一個無限迴圈中。
package main import ( "fmt" "time" ) func main() { channel1 := make(chan int) channel2 := make(chan string) go func() { for i := 0; i < 5; i++ { time.Sleep(time.Second) channel1 <- i } close(channel1) }() go func() { for i := 0; i < 5; i++ { time.Sleep(time.Second) channel2 <- fmt.Sprintf("Message %d", i) } close(channel2) }() for { select { case data1, ok := <-channel1: if ok { fmt.Println("Received from channel1:", data1) } else { fmt.Println("Channel1 closed") channel1 = nil } case data2, ok := <-channel2: if ok { fmt.Println("Received from channel2:", data2) } else { fmt.Println("Channel2 closed") channel2 = nil } } if channel1 == nil && channel2 == nil { break } } fmt.Println("Done") }
在這個範例中,建立了兩個通道channel1
和channel2
,分別用於傳送不同型別的資料。然後分別啟動兩個goroutine,每個goroutine向對應的通道傳送一些資料,然後關閉通道。其執行得結果如圖:
上述程式碼中 ok
是從通道的屬性中獲取的。在Go語言中,當從通道接收資料時,會返回兩個值:接收到的資料和一個表示通道是否已關閉的布林值。這個布林值就是ok
。 當通道已關閉且沒有資料可讀取時,會返回通道元素型別的零值和false
。當通道還未關閉且有資料可讀取時,會返回通道中的資料和true
。 因此,使用data, ok := <-channel
的語法可以同時接收通道中的資料和判斷通道是否已關閉。data
表示接收到的資料,ok
表示通道是否還有資料可讀取。如果ok
為false
,則表示通道已關閉,沒有資料可讀取。
在主函數中,我們使用無限迴圈和select
語句來持續監聽這兩個通道的操作。每次迴圈時,select
語句會選擇其中一個可用的通道進行操作。如果通道關閉,我們會將對應的通道設定為nil
,以便在後續的迴圈中跳過該通道的操作。當兩個通道都關閉,即channel1
和channel2
都為nil
時,我們跳出迴圈,程式結束。
執行上述程式碼,你會看到程式持續監聽兩個通道的操作,並列印接收到的資料,直到兩個通道都關閉。最後,程式輸出"Done"並結束。