使用chan的时候选择对象还是指针
使用chan的时候选择对象还是指针
2019-02-22 12:34 by 轩脉刃, … 阅读, … 评论, 收藏, 编辑
使用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