2013-05-16 135 views
29

旅途游具有此例如用于信道:http://tour.golang.org/#63通过引用传递通道隐含

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中的总和函数修改和更改存留功能终止后。显然c是通过引用传递的,但没有创建指向c的指针。渠道是否通过引用被隐式传递?

+0

是的,Go中的引用类型是'slice','map'和'channel'。传递这些信息时,您正在制作参考文件的副本。 *(字符串也作为引用类型实现,尽管它们是不可变的。)* – 2013-05-16 14:31:22

回答

41

从技术上讲,它们是被复制的,因为当你使用 make时,你在堆上分配了一些东西,所以它在技术上是一个指针。但指针类型没有公开,因此可以将它们视为引用类型。

EDIT:从规格:

内置函数make需要一个类型T,它必须是一个切片,地图或信道类型,任选地随后进行的特定类型的列表表达式。它返回类型T的值(不是* T)。内存初始化如初始值部分所述。

通道必须初始化才能使用。做这个,所以它可以用作参考类型。

这基本上意味着什么,你可以将它传递给函数并写入或读取它。一般的经验法则是,如果您使用make,new&,则可以将它传递给另一个函数而不复制底层数据。

因此,以下是 “参照” 类型:

  • 切片
  • 映射
  • 通道
  • 指针
  • 功能

只有数据类型(数字,布尔变量和结构等)在传递给函数时被复制。字符串是特殊的,因为它们是不可变的,但不会被值传递。这意味着以下将无法按预期方式工作:

type A struct { 
    b int 
} 
func f(a A) { 
    a.b = 3 
} 
func main() { 
    s := A{} 
    f(s) 
    println(s.b) // prints 0 
} 
+2

@tjameson:make并不意味着堆分配,slice实际上是作为一个结构实现的,并在传递时进行复制。 – zzzz

+0

@squint - 对。 ''array',我的意思是'make([] int,5)',但是我刚刚意识到这在技术上更具切片性。我的错。 – tjameson

+0

@jnml - 审查规范,我想这在技术上并非如此。我会编辑。 – tjameson

1

你可以说是,但是说“通道c在求和函数中被修改”并不是真正的正确术语。频道发送和接收不被认为是修改。

请注意,切片和贴图的行为方式类似,有关更多详细信息,请参见http://golang.org/doc/effective_go.html

此外,“通过引用传递”意味着可以在sum中对c进行分配,这会在总和之外改变它的值(而不是基础数据),但情况并非如此。

1

通道变量是引用,但它取决于您对'引用'的定义。 Language specification从不提及参考类型。

sum函数中没有通道(变量)被“修改”。发送到频道会改变其状态。

换句话说,是的通道被实现为指向某些运行时结构的指针。请注意,这对于引用语义来说是非常必要的。

编辑:上面的句子是为了读取:“请注意,这是而不是严格必要的参考语义。”,即。 “不”这个词去了MIA。对不起,最终造成的混乱。

5

Go中的所有内容都通过值并赋值。某些内置类型(包括通道类型和地图类型)表现为指向某些隐藏内部结构的不透明指针。并且可以通过频道或地图上的操作来修改该内部结构。它们开始为nil,这与nil指针类似。