微擎不現實陣列 切片和陣列的那些總結

2021-10-14 22:18:58 字數 3052 閱讀 5024

當 slice 作為函式引數時,就是乙個普通的結構體。其實很好理解:若直接傳 slice,在呼叫者看來,實參 slice 並不會被函式中的操作改變;若傳的是 slice 的指標,在呼叫者看來,是會被改變原 slice 的。

值的注意的是,不管傳的是 slice 還是 slice 指標,如果改變了 slice 底層陣列的資料,會反應到實參 slice 的底層資料。為什麼能改變底層陣列的資料?很好理解:底層資料在 slice 結構體裡是乙個指標,僅管 slice 結構體自身不會被改變,也就是說底層資料位址不會被改變。但是通過指向底層資料的指標,可以改變切片的底層資料,沒有問題。

通過 slice 的 array 欄位就可以拿到陣列的位址。在**裡,是直接通過類似s[i]=10這種操作改變 slice 底層陣列元素值。

另外,值得注意的是,go 語言的函式引數傳遞,只有值傳遞,沒有引用傳遞,面試的時候經常會問到。

先來看一段示例**:

package mainimport "fmt"func slicefunc(s int) }func main()   slicefunc(s)  fmt.println(s)}
執行程式輸出結果:

[2 4 6]
由結果可知:改變了原始 slice 的底層資料。這裡傳遞的是乙個 slice 的副本,在 slicefunc 函式中,s只是main函式中s的乙個拷貝。在 slicefunc 函式內部,對s的作用並不會改變外層main函式的s

要想真的改變外層slice,只有將返回的新的 slice 賦值到原始 slice,或者向函式傳遞乙個指向 slice 的指標。我們再看乙個例子:

執行程式輸出結果:

[1 1 1][1 1 1 100][1 1 1 100 100]
news是乙個新的slice,它是基於s得到的。因此它列印的是追加了乙個100之後的結果:[1 1 1 100]

所以上面的用法是錯的,不能編譯通過。

當原 slice 容量小於 1024 的時候,新 slice 容量變成原來的 2 倍;原 slice 容量超過 1024,新 slice 容量變成原來的1.25倍。
我在這裡先說結論:以上描述是錯誤的

為了說明上面的規律是錯誤的,我寫了一小段demo**:

執行結果:

在老 slice 容量小於1024的時候,新 slice 的容量的確是老 slice 的2倍。目前還算正確。

但是,當老 slice 容量大於等於1024的時候,情況就有變化了。當向 slice 中新增元素1280的時候,老 slice 的容量為1280,之後變成了1696,兩者並不是1.25倍的關係(1696/1280=1.325)。新增完1696後,新的容量2304當然也不是16961.25倍。

從前面彙編**我們也看到了,向 slice 追加元素的時候,若容量不夠,會呼叫growslice函式,所以我們直接看它的**:

// go 1.9.5 src/runtime/slice.go:82func growslice(et *_type, old slice, cap int) slice  else  else         }    }    // ……    capmem = roundupsize(uintptr(newcap) * ptrsize)    newcap = int(capmem / ptrsize)}
看到了嗎?如果只看前半部分,現在網上各種文章裡說的newcap的規律是對的。現實是,後半部分還對newcap作了乙個記憶體對齊,這個和記憶體分配策略相關。進行記憶體對齊之後,新 slice 的容量是要大於等於老 slice 容量的2倍或者1.25倍

最後,向growslice函式呼叫者返回乙個新的 slice,這個 slice 的長度並沒有變化,而容量卻增大了。

下面再來看個舉一反三的例子:

**切片對應狀態

s := int

s 只有乙個元素,[5]

s 擴容,容量變為2,[5, 7]

s 擴容,容量變為4,[5, 7, 9]。注意,這時 s 長度是3,只有3個元素

由於 s 的底層陣列仍然有空間,因此並不會擴容。這樣,底層陣列就變成了[5, 7, 9, 11]。注意,此時 s =[5, 7, 9],容量為4;x =[5, 7, 9, 11],容量為4。這裡 s 不變

這裡還是在 s 元素的尾部追加元素,由於 s 的長度為3,容量為4,所以直接在底層陣列索引為3的地方填上12。結果:s =[5, 7, 9],y =[5, 7, 9, 12],x =[5, 7, 9, 12],x,y 的長度均為4,容量也均為4

所以最後程式的執行結果為:

[5 7 9] [5 7 9 12] [5 7 9 12]
引申乙個問題:向乙個nil的slice新增元素會發生什麼?為什麼?

示例**歸檔路徑:

go context之使用技巧

微擎獲取openid 微擎借用許可權

微擎的借用許可權 最近公司有乙個專案,使用了微擎這套程式,並且在他的基礎上進行了二次開發,在二次開發中,發現了借用許可權留下來的小坑。許可權如何使用許可權獲得使用者資訊 訂閱號借用服務號的場景 場景公司現在有乙個服務號和很多訂閱號,又要想每個訂閱號也能獲取使用者的資訊,這時候就要用上借用許可權了。微...

微擎url模式解讀 微擎 URL 路由

入口指令碼程式獲取到到url中相關的get引數,解析後進行許可權判斷,然後呼叫相應的控制器處理這個請求。該過程就被稱為url路由 routing 約定及使用get 引數中的 c a do為微擎系統的路由引數,應當避免與系統引數衝突,在程式中可以使用 controller action do來獲取對應...

解決php session驗證碼不現實的問題

本人一開始老顯示不出來,顯示的是乙個裂了的,經查詢發現可能由以下幾種可能造成 1 在header content type image png 前加如下一段 ini set display errors off 本人就是由上面的問題造成。ini set display errors off head...