好湿?好紧?好多水好爽自慰,久久久噜久噜久久综合,成人做爰A片免费看黄冈,机机对机机30分钟无遮挡

主頁 > 知識庫 > Go語言中slice作為參數傳遞時遇到的一些“坑”

Go語言中slice作為參數傳遞時遇到的一些“坑”

熱門標簽:建造者2地圖標注 濱州自動電銷機器人排名 汕頭小型外呼系統 黃岡人工智能電銷機器人哪個好 浙江高頻外呼系統多少錢一個月 惠州電銷防封電話卡 釘釘有地圖標注功能嗎 鄭州亮點科技用的什么外呼系統 阿里云ai電話機器人

前言

相信看到這個題目,可能大家都覺得是一個老生常談的月經topic了。一直以來其實把握一個“值傳遞”基本上就能理解各種情況了,不過最近遇到了更深一點的“小坑”,與大家分享一下。

首先還是從最簡單的說起,看下面代碼:

func main() {
 a := []int{7,8,9}
 fmt.Printf("len: %d cap:%d data:%+v\n", len(a), cap(a), a)
 ap(a)
 fmt.Printf("len: %d cap:%d data:%+v\n", len(a), cap(a), a)
}

func ap(a []int) {
 a = append(a, 10)
}

以上代碼的輸出是什么呢?

我這里不賣關子了直接說,再調用ap函數進行append操作后,a依然是[]int{7,8,9}。原因很簡單,Go中沒有引用傳遞全是值傳遞,值傳遞意味著傳遞的是數據的拷貝。這句話新手可能稍微有點云里霧里,而實際情況又比較詭異,比如說下面代碼:

func main() {
  a := []int{7,8,9}
  fmt.Printf("len: %d cap:%d data:%+v\n", len(a), cap(a), a)
  ap(a)
  fmt.Printf("len: %d cap:%d data:%+v\n", len(a), cap(a), a)
}

func ap(a []int) {
  a[0] = 1
  a = append(a, 10)
}

這時ap后再輸出a,會看到a[0]變成了1,但a的cap依然是3,看起來10并沒有被append進去?

這看起來就比較匪夷所思了,不是說值傳遞嗎,為什么還是影響外部變量的值了呢?按理說要么都變要么都不變才說得過去啊。

這實際上并不是匪夷所思,因為Go和C不一樣,slice看起來像數組,實際上是一個結構體,在源碼中的數據結構是:

type slice struct {
 array unsafe.Pointer
 len int
 cap int
}

這個結構體其實也很好理解,array是一個真正的數組指針,指向一段連續內存空間的頭部,len和cap代表長度和容量。
換句話說,你看起來在代碼里傳參時寫的是ap(a []int),實際上在代碼編譯期,這段代碼變成了ap(a runtime.slice)
你可以嘗試這么理解,把ap(a)替換成ap(array: 0x123, len: 3, cap: 3) 。可以很明顯的看到,傳遞到ap函數的三個參數,僅僅是3個數值,并沒有和外部變量a建立任何引用關系。這便是值傳遞。

但是,你可能會疑惑,為什么我改了a[0]的值,也會在外面體現呢?其實看到這里你應該已經可以自己想明白了,因為array是一個地址值(比如0x123),這個地址傳入了ap函數,但是它代表的地址0x123和外部a的0x123是一個內存地址,這時候你修改a[0],實際上是修改0x123地址中存放的值,所以外部當然會受影響了。

舉個形象點的例子,假設你是火車站貨物管理員,你管理的是第1到第3節車廂(車廂是互通的)的裝卸貨貨。有一天你生病了,找個人(叫A)臨時來接手一下。但是火車的貨不是誰想碰就碰的,你得有證明才行。于是你把你手上的證明原件復印了一份給A,同時把第一節車廂的鑰匙給A。由于剛好那幾天比較忙,站長又讓A也負責第四節車廂,于是A也得到了車廂4的證明原件。一段時間后,你生病回來,你依然只有1到3節車廂的證件,你可以看到最近A在1到3車廂搞的事情,但是你沒有資格去4車廂。

以上例子應該可以很好的說明slice傳參的場景,記住,Go中只有值傳遞。

是不是就完事兒了呢?然而事情并沒有這么簡單。最近我工作時就遇到這個問題了。按照上面的舉例,雖然你沒有資格去查看4車廂,但是如果你好奇,你可以偷看啊,因為它們是連續的互通的,正如數組也是一段連續的內存,于是就有這樣的代碼:

func main() {
  a := []int{}
  a = append(a, 7,8,9)
  fmt.Printf("len: %d cap:%d data:%+v\n", len(a), cap(a), a)
  ap(a)
  fmt.Printf("len: %d cap:%d data:%+v\n", len(a), cap(a), a)
  p := unsafe.Pointer(a[2])
  q := uintptr(p)+8
  t := (*int)(unsafe.Pointer(q))
  fmt.Println(*t)
}

func ap(a []int) {
  a = append(a, 10)
}

雖然外部的cap和len并沒有改變,但是ap函數往同一段內存地址append了一個10,那我是不是可以用比較trick的方法去偷看呢?比如找到a[2]的地址,往后挪一個int的長度,就應該是ap函數新增的10了吧?這里需要注意,Go官網的server是32位的,所以在go playground執行這段代碼時,int是4字節。

執行結果和我預想的一樣!

但是問題接踵而至

func main() {
  a := []int{7,8,9}
  fmt.Printf("len: %d cap:%d data:%+v\n", len(a), cap(a), a)
  ap(a)
  fmt.Printf("len: %d cap:%d data:%+v\n", len(a), cap(a), a)
  p := unsafe.Pointer(a[2])
  q := uintptr(p)+8
  t := (*int)(unsafe.Pointer(q))
  fmt.Println(*t)
}

func ap(a []int) {
  a = append(a, 10)
}

這和上面一個例子唯一的區別就是slice一開始是用[]int{7,8,9}這種方式初始化。執行結果*t是3而不是10,這就比較困惑了。為啥?不是一段連續的內存空間嗎?

這里其實涉及到的問題是slice的growth問題,當append時發現cap不夠了,會重新分配空間,具體源碼參見 runtime/slice.go中的growslice函數。我這里就不講太多細節,只講結果。當發生growslice時,會給slice重新分配一段更大的內存,然后把原來的數據copy過去,把slice的array指針指向新內存。也就是說,假如之前的數據是存放到內存地址 0x0 0x8 0x10,當不發生growslice,新append的數值會存到0x18,然而當發生growslice,以前的所有數據被copy到新的地址0x1000 0x1008 0x1010,新append的值放到0x1018了。

這時候你就可以理解為什么有時候用unsafe能拿到數據,有時候拿不到了。或許你可以理解為什么這個包叫做unsafe了。不過unsafe不是真的unsafe,是說如果你使用的姿勢不對就非常容易unsafe。但是如果姿勢優雅,其實很safe。對于slice操作,如果要使用unsafe,千萬記得關注cap是否發送變化,它意味著內存的遷移

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

您可能感興趣的文章:
  • 深入解析Go語言編程中slice切片結構
  • go 判斷兩個 slice/struct/map 是否相等的實例
  • golang語言如何將interface轉為int, string,slice,struct等類型
  • Golang中的Slice與數組及區別詳解
  • Go 中 slice 的 In 功能實現探索
  • 深入理解go slice結構

標簽:昭通 阿壩 晉中 泰安 瀘州 東營 滄州 駐馬店

巨人網絡通訊聲明:本文標題《Go語言中slice作為參數傳遞時遇到的一些“坑”》,本文關鍵詞  語,言中,slice,作為,參數,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Go語言中slice作為參數傳遞時遇到的一些“坑”》相關的同類信息!
  • 本頁收集關于Go語言中slice作為參數傳遞時遇到的一些“坑”的相關信息資訊供網民參考!
  • 推薦文章
    主站蜘蛛池模板: 亲生(H)辣文h| 顶级尤物娇喘浪吟h| 日韩精品一区二区三区小说| 亚洲综合伦理一区| 女主胸大又放荡的辣文小说| 99久热视频在线精品| 嗯……好大| 男警察受呻吟双腿大开H漫画微博| 亚洲色图8p| 一把扯下肚兜 含着双乳| 捣烂宫口np失禁哭调教| 国产第十页| 亚洲AV无码乱码在线观看烟雨楼| 97精品依人久久久大香线蕉97软件的特点 | 国产福利在线观看第二区| 好湿好浪好紧好大好爽岳| 国产最新精品| 97国产精品人人爽人人做| 国产AV精品深夜福利网站 | 综合558欧美成人永久网站| 校花被绑起来灌水憋尿| gogo全球专业高清摄影| 野花免费观看完整动漫| yy4800青影院?理论片| 精产国品一区二区三区| 一级毛片在线播放免费| 桐柏县| 无遮无挡18禁啪啪成人小说男男| 欧美喷潮极限另类视频| 啊啊啊好深好爽| 麻豆精产国品一二三产区区别免费 | 全肉绿帽重口小说| 闺蜜的舌头伸进我的里面| 午夜小福利| 成全国产AV精品一区二区三区 | 啊灬啊灬啊灬快灬高潮了女学生| 麻花星空无限传媒有限公司| 日本a级高清影片| 视频区小说区图片区激情| 女教师日记4无删减版电影| 黑帮大佬与我的365日第二部|