Go語言規格說明書 之 select語句(Select statements)

go version go1.11 windows/amd64

 

本文爲閱讀Go語言中文官網的規則說明書(https://golang.google.cn/ref/spec)而做的筆記,介紹Go語言的 select語句(Select statements)。

 

前面寫了 Go語句、通道類型(也有翻譯爲 信道 的)、發送語句和接收操作符 的博文,再加上本文的 select語句,Go語言中 關於 信道和goroutine(協程) 的內容就學習完畢了。

閱讀參考鏈接1,可以獲得更多信息。

 

通過前面的學習,俺知道——select語句和switch語句不同的是,其case條件都是 通信操作——信道,select語句會被阻塞,也可以執行,執行時,只會 隨機選擇 多個 可執行case語句 中的一個 執行,如果每一個case語句都不可以執行,那麼,在有default語句時執行default,沒有default就一直阻塞。在使用select語句時,要特別注意每個case語句的通信是否可以執行,或者會阻塞,而這也是使用select語句的重難點。

 

下面是官文的翻譯(水平有限,歡迎指正、補充):

select語句用來 挑選一系列發送和接收操作中的一個來執行。它看起來和switch語句很像,但它的所有case子句 涉及到 通訊操作

在一個用於接收語句的case子句中,可以把接收語句的結果賦值給1個或2個變量,這裏的賦值可以使用 簡短變量聲明的方式(:=),這裏的接收表達式必須是一個接收操作(可以用圓括號括起來)。

select語句中最多可以出現一個default子句,而這個default子句可以出現在case子句列表的任意位置。

 

select語句將按照下面的步驟來執行:

1.對於所有case子句,接收操作的 信道操作數 和 信道(<- ch) 和 發送語句的右側表達式(ch <- x) 只會被 求值 1次,而且是按照源碼的順序。

結果 是 一系列信道 接收到或發送出,以及發送的相關值。

上句原文:The result is a set of channels to receive from or send to, and the corresponding values to send.

在求值過程中的任何負面效應,...

上句原文:Any side effects in that evaluation will occur irrespective of which (if any) communication operation is selected to proceed.

使用簡短變量聲明或賦值 的 接收語句左側的表達式 還沒有被求值。(本步驟翻譯存在問題)

2.如果一個或更多的通信可以執行,只有一個會被隨機選中(a uniform pseudo-random selection)執行。

否則(沒有通信可以執行),如果有default子句,則default子句會被選擇,,如果沒有default子句,那麼,select語句會被阻塞——直到任何一個case子句的通信可以執行。

3.除非選擇的語句是default子句,否則,選擇的case子句的通信操作會被執行(翻譯不太準確)。

4.如果選擇的case子句是一個簡短聲明或賦值的接收操作,那麼,其左側的表達式會被求值,並且接收到的值(1個或2個)會被賦值給左側表達式。

5.被選擇的case子句下的語句列表被執行。

 

說明,上面的翻譯有問題,也說明自己不是很理解,尤其是第一步,有些不明所以。還需要更多理解,後面再找機會完善(可能)。另外,原文中的proceed翻譯有問題,其和block是相對的。

 

由於和值爲 nil 的信道通信是不會得到執行的,因此,如果select語句中只有 值爲 nil 的信道 的 發送和接收操作的話,select語句將會永久被阻塞。

 

官文示例:

var a []int
var c, c1, c2, c3, c4 chan int // 信道只是 被聲明,但沒有被初始化,值爲nil,因此,下面的select語句的case子句會被阻塞,因爲有default子句,因此,輸出no communication
var i1, i2 int
select {
case i1 = <-c1:
	print("received ", i1, " from c1\n")
case c2 <- i2:
	print("sent ", i2, " to c2\n")
case i3, ok := (<-c3):  // same as: i3, ok := <-c3
	if ok {
		print("received ", i3, " from c3\n")
	} else {
		print("c3 is closed\n")
	}
case a[f()] = <-c4:
	// same as:
	// case t := <-c4
	//	a[f()] = t
default:
	print("no communication\n")
}

for {  // send random sequence of bits to c
	select {
	case c <- 0:  // note: no statement, no fallthrough, no folding of cases
	case c <- 1:
	}
}

select {}  // block forever

 

參考鏈接

1.RUNOOB.COM 之 Go 語言 select 語句

 

後記

本文得分:50。

雖然學習了 信道和協程 相關內容,可是,自己對如何使用它們還是處於 模糊不清 狀態的。該怎麼進階呢?看代碼?看官文Effective Go的相關內容?

還要琢磨清楚 一些代碼的具體運行原理。

目前自己學習的水平,可以用Golang來解決什麼問題呢?怎麼用它最特色的 信道和協程 呢?

信道和協程 的設計,到底有什麼好處?爲何Docker是使用Go開發的?不用Go,能用其它編程語言開發出來嗎?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章