通道(Channel)是Go語言中一種很是獨特的數據結構。它可用於在不一樣Goroutine之間傳遞類型化的數據,而且是併發安全的。相比之下,咱們以前介紹的那些數據類型都不是併發安全的。這一點須要特別注意。
Goroutine(也稱爲Go程序)能夠被看作是承載可被併發執行的代碼塊的載體。它們由Go語言的運行時系統調度,並依託操做系統線程(又稱內核線程)來併發地執行其中的代碼塊。至於怎樣編寫這樣的代碼塊以及怎樣驅動這樣的代碼塊執行,咱們先按下不表。
通道類型的表示方法很簡單,僅由兩部分組成,以下:緩存
chan T
在這個類型字面量中,左邊是表明通道類型的關鍵字chan
,而右邊則是一個可變的部分,即表明該通道類型容許傳遞的數據的類型(或稱通道的元素類型)。這兩部分之間須要以空格分隔。
與其它的數據類型不一樣,咱們沒法表示一個通道類型的值。所以,咱們也沒法用字面量來爲通道類型的變量賦值。咱們只能經過調用內建函數make
來達到目的。make
函數可接受兩個參數。第一個參數是表明了將被初始化的值的類型的字面量(好比chan int
),而第二個參數則是值的長度。例如,若咱們想要初始化一個長度爲5
且元素類型爲int
的通道值,則須要這樣寫:安全
make(chan int, 5)
順便說一句,實際上make
函數也能夠被用來初始化切片類型或字典類型的值。數據結構
確切地說,通道值的長度應該被稱爲其緩存的尺寸。換句話說,它表明着通道值中能夠暫存的數據的個數。注意,暫存在通道值中的數據是先進先出的,即:越早被放入(或稱發送)到通道值的數據會越先被取出(或稱接收)。
下面,咱們聲明一個通道類型的變量,併爲其賦值:併發
ch1 := make(chan string, 5)
這樣一來,咱們就可使用接收操做符<-
向通道值發送數據了。固然,也可使用它從通道值接收數據。例如,若是咱們要向通道ch1
發送字符串"value1"
,那麼應該這樣作:函數
ch1 <- "value1"
另外一方面,咱們若想從ch1
那裏接收字符串,則要這樣:spa
<- ch1
這時,咱們能夠直接把接收到的字符串賦給一個變量,如:操作系統
value := <- ch1
與針對字典值的索引表達式同樣,針對通道值的接收操做也能夠有第二個結果值。請看下面的示例:線程
value, ok := <- ch1
這樣作的目的一樣是爲了消除與零值有關的歧義。這裏的變量ok
的值一樣是bool
類型的。它表明了通道值的狀態,true
表明通道值有效,而false
則表明通道值已無效(或稱已關閉)。更深層次的緣由是,若是在接收操做進行以前或過程當中通道值被關閉了,則接收操做會當即結束並返回一個該通道值的元素類型的零值。按照上面的第一種寫法,咱們無從判斷接收到零值的緣由是什麼。不過,有了第二個結果值以後,這種判斷就好作了。
說到關閉通道值,咱們能夠經過調用內建函數close
來達到目的,就像這樣:code
close(ch1)
請注意,對通道值的重複關閉會引起運行時恐慌。這會使程序崩潰。因此必定要避免這種狀況的發生。另外,在通道值有效的前提下,針對它的發送操做會在通道值已滿(其中緩存的數據的個數已等於它的長度)時被阻塞。而向一個已被關閉的通道值發送數據會引起運行時恐慌。另外一方面,針對有效通道值的接收操做會在它已空(其中沒有緩存任何數據)時被阻塞。除此以外,還有幾條與通道的發送和接收操做有關的規則。不過在這裏咱們記住上面這三條就能夠了。
最後,與切片和字典類型相同,通道類型屬於引用類型。它的零值即爲nil
。索引