Golang 教學系列 - channel 裡面資料什麼都能放?單雙向 channel 的差別?

上次講了 channel 是什麼以及如何宣告以及還有一些要注意的情況:Golang 教學系列 - 何謂 Channel? 先從宣告 Channel 開始學起,今天這篇文章要講的是 channel 裡面的資料可以放怎樣的型態及如何運用,還有單雙向 channel 的差別等等。

想要看更詳細的講解,可以參考我的影片:Golang 教學系列 - channel 裡面資料什麼都能放?單雙向 channel 的差別?| 肯尼攻城獅

channel 可以放的資料型態

直接上一個例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type user struct {
email string
name string
gender string
}

func main() {
stringChan := make(chan string, 3)
stringChan <- "hello world"
u := user{
"[email protected]",
"kenny",
"male",
}
userChan := make(chan user, 1)
fmt.Println(<- userChan)
fmt.Println(userChan)
}

以上面的例子來看,channel 裡面可以放 string,也可以放自定義的 struct:user

而根據以上的運行,可以知道宣告 channel 的時候回傳的時候是回傳 pointer 的,因此我們在透過 func 傳遞 channel 參數的時候是不需要再加 * 號的。

所以可以用這個例子來做示範:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type user struct {
email string
name string
gender string
}

func main() {
stringChan := make(chan string, 3)
stringChan <- "hello world"
userChan := make(chan user, 1)
test(userChan)
fmt.Println(<- userChan)
fmt.Println(userChan)
}

func test(userChan chan user) {
u := user{
"[email protected]",
"kenny",
"male",
}
userChan <- u
}

所以根據 func test 就可以知道單純傳 channel 參數就可以了。

channel 裡面放 interface 呢?

來看個例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

type dog struct {
name string
gender string
}

func main() {
allChan := make(chan interface{}, 3)
allChan <- dog{"jack", "male"}
allChan <- 1
allChan <- "hello World"

d := <- allChan
fmt.Println(d)
}

在宣告 channel 的時候,裡面 element 可以放的是 interface 型態,所以這就代表什麼型態的元素都可以放進去這個 channel。所以以這個例子來看的話就是自定義的 dog struct,int,string 都可以放進去這個 channel。

單雙向 channel 介紹

來看個例子:

1
2
3
4
5
6
7
8
package main

func main() {
intChan := make(chan <- int, 3)
stringChan := make(<- chan int, 3)
intChan <- 1
<- stringChan
}

所謂單雙向的意思是在於說,單向是有分兩種:

  1. 只能往 channel 裡面送資料
  2. 只能從 channel 取出資料

而雙向的意思就是說送資料跟取資料的操作都是可以的。

所以宣告單向 channel 的方式就如同 intChan跟stringChan 的方式,如果以 chan <- int 這樣的方式代表是只能往 channel 裡面送 int 型態的意思,而如果是 <- chan int 的話就代表只能從 channel 裡面取出 int 型態的 element 的意思。

如果對 intChan 做取出資料的操作的話:<- intChan 的話在編譯的時候就會被抓出錯誤而無法運行程式。會秀出這個錯誤訊息:

Invalid operation: <- intChan (receive from send-only type chan<- int) 而如果對 stringChan做出stringChan <- "Hello" 也會出現這樣的錯誤。

這邊特地提醒:

在 Golang 中對 channel 的送資料跟取資料的英文單字會採用

  • send 代表往 channel 裡面送資料
  • receive 代表從 channel 裡面取出資料

所以在根據以上錯誤訊息就會很清楚了。

單雙向的 channel 的優缺點?

我個人認為優點在於是對於開發者上的規範,以及情境上的定義來決定 channel 是否要單向還是雙向。

總結

今天主要是介紹單雙向 channel 的差別及宣告方式,下篇文章要教的是關閉 channel 是會帶來怎樣的影響以及如何去 for loop 取出 channel 裡面的資料。