亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

是使用引用還是復制指向切片的指針?

是使用引用還是復制指向切片的指針?

Go
海綿寶寶撒 2021-09-10 15:31:21
我發現我的代碼有不同的結果,如下所示,這是一個指向 Go.Tour 編譯器(http://tour.golang.org/welcome/1)和我的本地編譯器(Go 版本 1.4)之間的幻燈片的指針哪一個是正確的?而且我還想知道我的代碼 p1、p2 之間的指針是如何工作的?因為地址似乎沒有移動,但 p1 使用引用,而 p2 使用復制。package mainimport "fmt"func main() {    var a []int    var b []int    a = append(a, 0)    b = append(b, 0)    p := &a[0]    fmt.Printf("a[0] = %d pointer=%d, p = %d \n", a[0], &a[0], *p)    a[0] = 2    fmt.Printf("a[0] = %d pointer=%d, p = %d \n", a[0], &a[0], *p)    /*        a[0] = 0, p = 0        a[0] = 2, p = 2    */    var c []int    var d []int    c = append(c, 0)    d = append(d, 0)    p2 := &c[0]    fmt.Printf("c[0]=%d pointer=%d, p2 = %d\n", c[0], &c[0], *p2)    c = append(c, 1)    c[0] = 2    fmt.Printf("c[0]=%d pointer=%d, p2 = %d\n", c[0], &c[0], *p2)    /*         c[0]=0, p2 = 0        c[0]=2, p2 = 0      copy the same code run in http://tour.golang.org/welcome/1 will get.        c[0]=0, p2 = 0        c[0]=2, p2 = *2*  << why??    */}更新:我使用指向切片的指針的原因是我試圖測試在 Go 的 Web 端存在 RUST 的向量 push_pack 問題。請參閱http://doc.rust-lang.org/nightly/intro.html#ownership。
查看完整描述

2 回答

?
RISEBY

TA貢獻1856條經驗 獲得超5個贊

首先,對于任何帶有切片的內容,我建議您閱讀Go Slices: usage and internals。簡短的故事是 Go 使用 append 處理切片的容量可能很不穩定。


給定的切片變量具有三個組成部分:指向數據數組的底層指針、長度和容量。已經有很多關于差異的說法,但這里的重要部分是長度是(有效)當前使用的底層內存緩沖區的部分,容量是底層緩沖區的整體大小。這是一個不精確的定義,但它在實踐中效果很好。


神秘的下一部分是append內置函數。append 的功能有時實際上有點難以推理,這可能是 Go 中最大的問題之一:


如果底層緩沖區足夠大(cap > len),只需將 len 增加要添加的元素數并將數據放入新空間。

如果底層緩沖區不夠大,則分配一個更大容量的新緩沖區,將舊緩沖區復制到新緩沖區中,然后添加所有新元素。

2 的最大癥結在于,在追加之后對同一個切片進行兩次任意操作,很難知道舊的或新的內存緩沖區是否被先驗地影響。確實,讓我們試試這個:


var c []int

var d []int

c = append(c, 0)

d = append(d, 0)

p2 := &c[0]

fmt.Printf("c[0]=%d pointer=%d, p2 = %d\n", c[0], &c[0], *p2)

c = append(c, 1)

c[0] = 2

fmt.Printf("c[0]=%d pointer=%d, p2 = %d\n", c[0], &c[0], *p2)

c = append(c, 1)

c[0] = 25

fmt.Printf("c[0]=%d pointer=%d, p2 = %d\n", c[0], &c[0], *p2)



你會得到c[0]=25, p2=2。我們只添加了一個語句,突然間指針和切片值發散了!


這意味著上限發生了變化,或者更確切地說,使用了新的緩沖區。實際上,cap(c)在第一個 append 之后但在第三個之前打印,將產生2. 這意味著當將單個元素附加到容量為 0 的切片時,Go 會初始化 [footnote] 長度為 1 和容量為2的切片。所以在第二次追加之后沒有分配新的緩沖區,因為有空間。這就是為什么p2和c[0]在第二次追加之后是一樣的,但在第三次之后是一樣的。


一般來說,雖然切片和對內存中特定位置的引用的確切規則是一致的,但在實踐中切片增長的行為非常挑剔,通常最好永遠不要依賴指向切片值(或兩個切片變量)的指針具有相同的底層緩沖區),除非您計劃從不使用 append,或者將緩沖區預先分配make到使用 append 永遠不會重新分配的大小。


[腳注] 不完全正確,我想給出一個巨大的警告,即 append 后的確切容量取決于實現。請不要依賴 APPEND 導致編譯器之間或什至不同編譯器目標之間一致的容量


查看完整回答
反對 回復 2021-09-10
  • 2 回答
  • 0 關注
  • 148 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號