<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    咖啡伴侶

    呆在上海
    posts - 163, comments - 156, trackbacks - 0, articles - 2

    Go語言的傳參和傳引用

    Posted on 2013-09-16 09:23 oathleo 閱讀(4009) 評論(1)  編輯  收藏 所屬分類: Golang

    Go語言的傳參和傳引用[OSC源創會主題補充1]

    66人收藏此文章, 我要收藏發表于2天前(2013-09-14 22:10) , 已有1496次閱讀 ,共12個評論

    OSC源創會主題補充系列:

    1. Go語言的傳參和傳引用
    2. Go語言的類型轉換和類型斷言

    Go語言規范雖然很簡單, 但是深入掌握Go語言卻需要很多底層知識.

    本來第20期的武漢OSC源創會有Go語言的專題講座, 誰知道說取消就取消了.

    我最近也整理了一些Go語言資料, 有Go語言的歷史/現狀/未來發展的八卦和Go語言常見的問題和陷阱兩個部分, 本來打算OSC源創會能和武漢的Gopher分享 下的, 誰知道(由于不是贊助商也不是微軟的大牛)主辦方根本不給任何的機會.

    100+人數的交流會基本都是扯淡, 還是小規模的討論沙龍比較靠譜, 以后再也不會去OSC源創會當聽眾了.

    現在計劃將各個小問題暫時作為博客發表.

    傳參和傳引用的問題

    很多非官方的文檔和教材(包括一些已經出版的圖書), 對Go語言的傳參和引用的講解 都有很多問題. 導致眾多Go語言新手對Go的函數參數傳參有很多誤解.

    而傳參和傳引用是編程語言的根本問題, 如果這個問題理解錯誤可能會導致很多問題.

    slice不是引用!

    首先, Go語言的函數調用參數全部是傳值的, 包括 slice/map/chan 在內所有類型, 沒有傳引用的說法.

    具體請看Go語言的規范:

    After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution.

    from: http://golang.org/ref/spec#Calls

    什么叫引用?

    比如有以下代碼:

    var a Object doSomething(a) // 修改a的值 print(a) 

    如果函數doSomething修改a的值, 然后print打印出來的也是修改后的值, 那么就可以認為doSomething是通過引用的方式使用了參數a.

    為什么slice不是引用?

    我們構造以下的代碼:

    func main() {     a := []int{1,2,3}     fmt.Println(a)     modifySlice(a)     fmt.Println(a) }  func modifySlice(data []int) {     data = nil } 

    其中modifySlice修改了切片a, 輸出結果如下:

    [1 2 3] [1 2 3] 

    說明a在調用modifySlice前后并沒有任何變化, 因此a必然是傳值的!

    為什么很多人誤以為slice是引用呢?

    可能是 因為很多新接觸Go語言的新手, 看到Go語言的文檔說Go的切片和C語言的數組類型, 而C語言的數組是傳地址的(注意: 不是傳引用!).

    下面這個代碼可能是錯誤的根源:

    func main() {     a := []int{1,2,3}     fmt.Println(a)     modifySliceData(a)     fmt.Println(a) }  func modifySliceData(data []int) {     data[0] = 0 } 

    輸出為:

    [1 2 3] [0 2 3] 

    函數modifySliceData確實通過參數修改了切片的內容.

    但是請注意: 修改通過函數修改參數內容的機制有很多, 其中傳參數的地址就可以修改參數的值(其實是修改參數中指針指向的數據), 并不是只有引用一種方式!

    傳指針和傳引用是等價的嗎?

    比如有以下代碼:

    func main() {     a := new(int)     fmt.Println(a)     modify(a)     fmt.Println(a) }  func modify(a *int) {     a = nil } 

    輸出為:

    0xc010000000 0xc010000000 

    可以看出指針a本身并沒有變化. 傳指針或傳地址也只能修改指針指向的內存的值, 并不能改變指針本身在值.

    因此, 函數參數傳傳指針也是傳值的, 并不是傳引用!

    所有類型的函數參數都是傳值的!

    包括slice/map/chan等基礎類型和自定義的類型都是傳值的.

    但是因為slicemap/chan底層結構的差異, 又導致了它們傳值的影響并不完全等同.

    重點歸納如下:

    • GoSpec: the parameters of the call are passed by value!
    • map/slice/chan 都是傳值, 不是傳引用
    • map/chan 對應指針, 和引用類似
    • slice 是結構體和指針的混合體

    • slice 含 values/count/capacity 等信息, 是按值傳遞

    • slice 中的 values 是指針, 按值傳遞
    • 按值傳遞的 slice 只能修改values指向的數據, 其他都不能修改

    • 以指針或結構體的角度看, 都是值傳遞!

    那Go語言有傳引用的說法嗎?

    Go語言其實也是有傳引用的地方的, 但是不是函數的參數, 而是閉包對外部環境是通過引用訪問的.

    查看以下的代碼:

    func main() {     a := new(int)     fmt.Println(a)     func() {         a = nil     }()     fmt.Println(a) } 

    輸出為:

    0xc010000000 <nil> 

    因為閉包是通過引用的方式使用外部環境的a變量, 因此可以直接修改a的值.

    比如下面2段代碼的輸出是截然不同的, 原因就是第二個代碼是通過閉包引用的方式輸出i變量:

    for i := 0; i < 5; i++ {     defer fmt.Printf("%d ", i)     // Output: 4 3 2 1 0 }  fmt.Printf("\n")     for i := 0; i < 5; i++ {     defer func(){ fmt.Printf("%d ", i) } ()     // Output: 5 5 5 5 5 } 

    像第二個代碼就是于閉包引用導致的副作用, 回避這個副作用的辦法是通過參數傳值或每次閉包構造不同的臨時變量:

    // 方法1: 每次循環構造一個臨時變量 i for i := 0; i < 5; i++ {     i := i     defer func(){ fmt.Printf("%d ", i) } ()     // Output: 4 3 2 1 0 } // 方法2: 通過函數參數傳慘 for i := 0; i < 5; i++ {     defer func(i int){ fmt.Printf("%d ", i) } (i)     // Output: 4 3 2 1 0 } 

    總結

    • 函數參數傳值, 閉包傳引用!
    • slice 含 values/count/capacity 等信息, 是按值傳遞
    • 按值傳遞的 slice 只能修改values指向的數據, 其他都不能修改
    • slice 是結構體和指針的混合體

    Feedback

    # re: Go語言的傳參和傳引用  回復  更多評論   

    2014-09-19 00:34 by ranh
    結論正確,過程不對,slice是因為底層數組相同所有有傳引用的效果,你舉例的slice是array好吧
    主站蜘蛛池模板: 亚洲欧美日韩一区二区三区| 亚洲制服丝袜精品久久| 久久久久亚洲AV无码去区首| 人成午夜免费视频在线观看| 亚洲视频在线观看| 欧洲精品99毛片免费高清观看| 亚洲第一福利视频| 国产成人精品一区二区三区免费| 亚洲国产精品一区二区久久hs| 99久久免费国产精精品| 亚洲av永久无码制服河南实里| 亚洲免费观看视频| 亚洲经典在线观看| 精品久久久久久久久免费影院| 亚洲黄页网在线观看| 日韩成全视频观看免费观看高清| 国产精品亚洲一区二区三区久久| 亚洲熟女乱综合一区二区| 中出五十路免费视频| 久久青青草原亚洲av无码app| 免费人成网站在线观看10分钟| 亚洲国产视频久久| 亚洲AV中文无码乱人伦在线视色| a在线视频免费观看在线视频三区| 国产亚洲精品a在线观看app| 亚洲一级免费毛片| 天天综合亚洲色在线精品| 4338×亚洲全国最大色成网站| 免费高清国产视频| 亚洲一区二区三区亚瑟| 免费一级毛片在线观看| baoyu777永久免费视频| 亚洲免费在线视频播放| 日本不卡在线观看免费v| 国产在线观看xxxx免费| 亚洲国产精品日韩在线观看| 亚洲 无码 在线 专区| 2019中文字幕免费电影在线播放| 亚洲欧洲国产综合AV无码久久| 中文字幕一精品亚洲无线一区| 国产免费久久精品99re丫y|