使用chan的時候選擇對象還是指針
今天在寫代碼的時候遇到一個問題,在創建一個通道的時候,不確定創建的通道是使用chan A還是chan *A。
思考了一下,覺得這個應該和函數一樣是一個值傳遞還是參數傳遞的問題。然后寫了個play驗證了一下。
package main
import (
"fmt"
"time"
)
type B struct {
Value int
}
type A struct {
Bv B
}
func main() {
ch := make(chan *A)
b := B{1}
a := A{Bv:b}
go func(ch chan *A){
for {
select {
case a := <-ch:
a.Bv.Value = 2
}
}
}(ch)
ch <- &a
time.Sleep(2 * time.Second)
fmt.Println(a)
}
這里a.Bv.Value的值改了。 但是如果我這里的ch是make(chan A)的話,則打印出來的值為1了。
事實證明確實是這樣。再去源碼里面看看。
chan的結構是在src/runtime/chan.go 的hchan。我們就看chan.go里面的recv方法
func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
這個函數就是<-ch 的時候調用的。這里的c代表的就是我們使用的這個chan, ep代表的是ch傳輸出來的數據存儲的位置。
它在從channel中獲取數據的時候調用的是
recv(c, sg, ep, func() { unlock(&c.lock) }, 3)
看到這個函數里面,就可以看到使用的是typedmemmove 這個函數,這個函數就是c中的memmove。
將原先的數據,直接拷貝到目標內存中。所以這里說明channel是進行值拷貝的。
總結
基本上,chan的使用,如果是結構體的話,建議能使用指針就使用指針。
備注
本文golang代碼基於go1.11.4
