go tour有关于频道的示例:https://tour.golang.org/concurrency/2
package main
import "fmt"
func sum(a []int, c chan int) {
sum := 0
for _, v := range a {
sum += v
}
c <- sum // send sum to c
}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
通道c在sum函数中被修改,并且在函数终止后更改仍然存在。显然c是通过引用传递的,但没有创建指向c的指针。是否通过引用隐式传递了通道?
答案 0 :(得分:55)
从技术上讲它们是被复制的,因为当你使用 make
时,你在堆上分配一些东西,所以它在技术上是一个幕后指针。但是指针类型没有公开,因此可以将它们视为引用类型。
编辑:来自规范:
内置函数make采用类型T,它必须是切片,地图或通道类型,可选地后跟类型特定的表达式列表。它返回类型T的值(不是* T)。内存初始化,如初始值一节中所述。
必须先初始化通道才能使用它。 Make这样做,因此它可以用作参考类型。
这基本上意味着你可以将它传递给一个函数并写入或读取它。一般的经验法则是,如果您使用make
,new
或&
,则可以将其传递给其他函数,而无需复制基础数据。
所以,以下是“参考”类型:
传递给函数时,只复制数据类型(数字,bool和结构等)。字符串是特殊的,因为它们是不可变的,但不是通过值传递的。这意味着以下内容无法按预期工作:
type A struct {
b int
}
func f(a A) {
a.b = 3
}
func main() {
s := A{}
f(s)
println(s.b) // prints 0
}
答案 1 :(得分:9)
Go中的所有内容都会传递并按值分配。某些内置类型(包括通道类型和地图类型)表现为指向某些隐藏内部结构的不透明指针。并且可以通过通道或地图上的操作来修改内部结构。它们以nil
开头,类似于nil
指针。
答案 2 :(得分:1)
你可以说是的,但是说“在和函数中修改了通道c”并不是真正正确的术语。频道发送和接收并不是真正被视为修改。
请注意,切片和地图的行为方式类似,有关详细信息,请参阅http://golang.org/doc/effective_go.html。
同样“通过引用传递”意味着可以在c
中对sum
进行赋值,这将在sum之外改变它的值(而不是它的基础数据),但情况并非如此
答案 3 :(得分:1)
通道变量是引用,但它取决于您对“引用”的定义。 Language specification从未提及引用类型。
sum
函数中没有'修改'通道(变量)。发送到频道会改变其状态。
换句话说,是的,通道被实现为指向某个运行时结构的指针。请注意,这对于引用语义是非常必要的。
编辑:上面的句子意思是:“请注意, 对参考语义来说是非常必要的。”,即。 “不”这个词就是MIA。对不起最终造成的混淆。