中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang中函數傳參是否存在引用傳遞

發布時間:2021-12-09 10:29:31 來源:億速云 閱讀:129 作者:柒染 欄目:大數據

今天就跟大家聊聊有關Golang中函數傳參是否存在引用傳遞,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

Go里邊函數傳參只有值傳遞一種方式

值傳遞

值傳遞是指在調用函數時將實際參數復制一份傳遞到函數中,這樣在函數中如果對參數進行修改,將不會影響到實際參數。

概念總給人一種教科書的感覺,寫點代碼驗證下。

func main() {
    a := 10
    fmt.Printf("%#v\n", &a) // (*int)(0xc420018080)
    vFoo(a)
}

func vFoo(b int) {    fmt.Printf("%#v\n", &b) // (*int)(0xc420018090)
}

注釋內容是我機器的輸出,你如果運行會得到不一樣的輸出

根據代碼來解釋下,所謂的值傳遞就是:實參 a 在傳遞給函數 vFoo 的形參 b 后,在 vFoo 的內部,b 會被當作局部變量在棧上分配空間,并且完全拷貝 a 的值。

代碼執行后,我們看到的結果便是:a、b擁有完全不同的內存地址, 說明他們雖然值相同(b拷貝的a,值肯定一樣),但是分別在內存中不同的地方,也因此在函數 vFoo 內部如果改變 b 的值,a 是不會受到影響的。

Golang中函數傳參是否存在引用傳遞

圖中左側是還未調用時,內存的分配,右側是調用函數后內存分別分配的變量。這里需要注意,就算vFoo的參數名字是a,實參與形參也分別有自己的內存空間,因為參數的名字僅僅是給程序員看的,上篇文章已經說清楚了。

指針傳遞

形參為指向實參地址的指針,當對形參的指向操作時,就相當于對實參本身進行的操作。

是不是云里霧里的?還是通過代碼結合來分析所謂的指針傳遞。

func main() {
    a := 10
    pa := &a
    fmt.Printf("value: %#v\n", pa) // value: (*int)(0xc420080008)
    fmt.Printf("addr: %#v\n", &pa) // addr: (**int)(0xc420088018)
    pFoo(pa)
}

func pFoo(p * int) {    fmt.Printf("value: %#v\n", p) // value: (*int)(0xc420080008)    fmt.Printf("addr: %#v\n", &p) // addr: (**int)(0xc420088028)
}

定義了一個變量 a,并把地址保存在指針變量 pa 里邊了。按照我們定的結論,Go中只有值傳遞,那么指針變量pa傳給函數的形參p后,形參將會是它在棧上的一份拷貝,他們本身將各自擁有不同的地址,但是二者的值是一樣的(都是變量a的地址)。上面的注釋部分是我程序運行后的結果,pa 與 p 的地址各自互不相關,說明在參數傳遞中發生了值拷貝。

在函數 pFoo 中,形參 p 的地址與實參 pa 的地址并不一樣,但是他們在內存中的值都是變量 a 的地址,因此可以通過指針相關的操作來改變a的值。

Golang中函數傳參是否存在引用傳遞

圖中 &a 表示a的地址,值為: 0xc420080008

引用傳遞

所謂引用傳遞是指在調用函數時將實際參數的地址傳遞到函數中,那么在函數中對參數所進行的修改,將影響到實際參數。

由于 Go 里邊并不存在引用傳遞,我們常常看到說 Go 中的引用傳遞也是針對:SliceMapChannel 這幾種類型(這是個錯誤觀點),因此為了解釋清楚引用傳遞,先勞煩大家看一段 C++ 的代碼(當然非常簡單)。

void rFoo(int & ref) {
   printf("%p\n", &ref);// 0x7ffee5aef768
}
   
int main() {
   int a = 10;
   printf("%p\n", &a);// 0x7ffee7307768    int & b = a;
   printf("%p\n", &b);// 0x7ffee5aef768    rFoo(b);
   return 0; }

這里就是簡單的在main中定義一個引用,然后傳給函數 rFoo,那么來看看正統的引用傳遞是什么樣的?

這里 b 是 a 的別名(引用,不清楚的可以看我上篇文章),因此a、b必定具備相同的地址。那么按照引用傳遞的定義,實參 b 傳給形參 ref 之后,ref 將是 b 的別名(也即a、b、ref都是同一個變量),他們將擁有相同地址。通過在 rFoo 函數中的打印信息,可以看到三者具有完全形同的地址,這是所謂的引用傳遞。

Go中沒有引用傳遞

Go中函數調用只有值傳遞,但是類型引用有引用類型,他們是:slicemapchannel。來看看官方的說法:

There’s a lot of history on that topic. Early on, maps and channels were syntactically pointers and it was impossible to declare or use a non-pointer instance. Also, we struggled with how arrays should work. Eventually we decided that the strict separation of pointers and values made the language harder to use.  Changing these types to act as references to the associated, shared data structures resolved these issues. This change added some regrettable complexity to the language but had a large effect on usability: Go became a more productive, comfortable language when it was introduced.

大概意思是說:最開始用的是指針語法,由于種種原因改成了引用,但是這個引用與C++的引用是不同的,它是共享關聯數據的結構。關于這個問題的深入討論我會放到 slice 相關文章中進行討論,現在回到今天討論的主題。

那么Go的引用傳遞源起何處?我覺得讓大家誤解的是,map、slice、channel這類引用類型在傳遞到函數內部,可以在函數內部對它的值進行修改而引起的誤會。

針對這種三種類型是 by value 傳遞,我們用 slice 來進行驗證。

func main() {
    arr := [5]int{1, 3, 5, 6, 7}
    fmt.Printf("addr:%p\n", &arr)// addr:0xc42001a1e0
    s1 := arr[:]
    fmt.Printf("addr:%p\n", &s1)// addr:0xc42000a060

    changeSlice(s1)
}

func changeSlice(s []int) {    fmt.Printf("addr:%p\n", &s)// addr:0xc42000a080    fmt.Printf("addr:%p\n", &s[0])// addr:0xc42001a1e0
}

代碼中定義了一個數組 arr,然后用它生成了一個slice。如果go中存在引用傳遞,形參 s 的地址應該與實參 s1 一樣(上面c++的證明),通過實際的情況我們發現它們具備完全不同的地址,也就是傳參依然發生了拷貝——值傳遞。

但是這里有個奇怪的現象,大家看到了 arr 的地址與 s[0] 有相同的地址,這也就是為什么我們在函數內部能夠修改 slice 的原因,因為當它作為參數傳入函數時,雖然 slice 本身是值拷貝,但是它內部引用了對應數組的結構,因此 s[0] 就是 arr[0] 的引用,這也就是能夠進行修改的原因。

  • Go 中函數傳參僅有值傳遞一種方式;

  • slicemapchannel都是引用類型,但是跟c++的不同;

  • slice能夠通過函數傳參后,修改對應的數組值,是因為 slice 內部保存了引用數組的指針,并不是因為引用傳遞。

看完上述內容,你們對Golang中函數傳參是否存在引用傳遞有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

南开区| 同德县| 池州市| 凤台县| 治多县| 广宗县| 社会| 霍城县| 海门市| 漠河县| 朔州市| 蕲春县| 东山县| 诏安县| 宜都市| 长海县| 合阳县| 璧山县| 南开区| 内黄县| 克拉玛依市| 博爱县| 汉阴县| 镇雄县| 汾西县| 望江县| 漳浦县| 阳谷县| 泰顺县| 龙泉市| 建湖县| 密山市| 阿克陶县| 清河县| 大渡口区| 大英县| 桓台县| 于都县| 西宁市| 比如县| 当阳市|