2013-05-16 65 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指針類似。