在 golang 文檔中,對數組與切片有一些詳細的講解,本文主要講解數組與切片的關係golang
因爲是我的理解,可能有些誤差,煩請指正
數組
golang 的數組比較簡單,咱們理解幾個概念便可bash
記住,咱們在此定義了一個 int 類型的數組,長度容量均爲 5,在後面的切片講解中,咱們將對此數組進行切片
數據結構
// 此定義的數組長度爲 5 ,那麼容量也會固定爲 5
arr := [5]int{0, 1, 2, 3, 4}
// 數組 p = 0xc00001c0f0,arr = [0 1 2 3 4],len = 5,cap = 5
fmt.Printf("數組 p = %p,arr = %+v,len = %d,cap = %d\n", &arr, arr, len(arr), cap(arr))
// 數組的索引都是從 0 開始的
// 0 1
fmt.Println(arr[0], arr[1])
複製代碼
咱們首先來建立一個對 arr
數組的一個切片app
** [1:3] 表示範圍從數組的索引 1 至 數組的索引 3,它是不包括 3 的,能夠簡單理解爲 index == 1 && index < 3 ** ** 當切片生成後,索引默認也是從 0 開始, 切片索引是 [0,1] 對應着數組的索引是 [1,2] **ui
arrSlice := arr[1:3]
// 切片 p = 0xc00000c060,arr = [1 2],len = 2,cap = 4
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice))
複製代碼
咱們上面有提到過,切片是對數組的一個引用,那麼咱們修改數組的值,切片會發生什麼呢?spa
// 把數組 index = 1 的值修改成 10
arr[1] = 10
// 切片 p = 0xc00000c060,arr = [10 2],len = 2,cap = 4
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice)
複製代碼
能夠看到,咱們切片對應的值也被修改成 10,切片的底層數據結構中存在的底層數組是對咱們上面數組作的引用傳遞
,關於引用傳遞和值傳遞你們應該仍是分的清的code
那麼對應的,咱們修改切片,數組也會發生相應的變化索引
// 一樣的道理,修改切片的值也會影響到底層數組
arrSlice[0] = 8
// 切片 p = 0xc00000c060,arr = [8 2],len = 2,cap = 4
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice))
// 數組 p = 0xc00001c0f0,arr = [0 8 2 3 4],len = 5,cap = 5
fmt.Printf("數組 p = %p,arr = %+v,len = %d,cap = %d\n", &arr, arr, len(arr), cap(arr))
複製代碼
上面說到,咱們修改切片或者是數組,都會有對應的變化,那麼咱們對切片進行追加呢?文檔
// 對切片追加
arrSlice = append(arrSlice, 11)
// 切片 p = 0xc00008a020,arr = [8 2 11],len = 3,cap = 4
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice))
// 數組 p = 0xc000090060,arr = [0 8 2 11 4],len = 5,cap = 5
fmt.Printf("數組 p = %p,arr = %+v,len = %d,cap = %d\n", &arr, arr, len(arr), cap(arr))
複製代碼
咱們能夠看到,數組的 index = 3 的值被修改成 11,我是這麼理解的:
[0,1]
對應着數組的 [1,2]
[0,1,2]
數組對應的索引是 [1,2,3]
經過上面的代碼,咱們能夠看到咱們的 cap 一直都是 4,爲何呢?這就要涉及到一個容量的計算公式了
建立時計算容量的公式爲:建立時的長度 * 2,咱們的長度是 2 ,計算出來的容量則爲 4
在追加時,會先判斷容量夠不夠,若是容量足夠則容量不變;若是超出容量那麼判斷長度是否小於 1024 ,小於則容量 * 2,大於則容量 * 1.25
這就是爲何咱們的容量一直是 4 的緣由
咱們一直在反覆提,切片是對數組的引用,那麼當我切片已經超出數組的範圍,會發生什麼呢?
咱們寫代碼操做一下
arrSlice = append(arrSlice, 12, 13, 14)
// 切片 p = 0xc00000c060,arr = [8 2 11 12 13 14],len = 6,cap = 8
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice))
// 數組 p = 0xc00001c0f0,arr = [0 8 2 11 4],len = 5,cap = 5
fmt.Printf("數組 p = %p,arr = %+v,len = %d,cap = %d\n", &arr, arr, len(arr), cap(arr))
複製代碼
在上面代碼中,咱們追加了三個值 12,13,14
。
咱們能夠看到,數組的值並無被修改,按照咱們上一步講的來講,應該數組的最後一位會變爲 12
,可是並無 這是一個很重要的概念,當咱們的切片容量大於底層數組容量時,會自動建立一個新的底層數組,取消對原數組的引用
當咱們切片取消對原數組引用時,咱們再去修改切片,並不會影響到原數組
arrSlice[0] = 18
// 切片 p = 0xc00008c020,arr = [18 2 11 12 13 14],len = 6,cap = 8
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice))
// 數組 p = 0xc000092060,arr = [0 8 2 11 4],len = 5,cap = 5
fmt.Printf("數組 p = %p,arr = %+v,len = %d,cap = %d\n", &arr, arr, len(arr), cap(arr))
複製代碼
根據查閱資料來看,大部分人都是說當被取消引用,而且也沒有別的地方去引用時,golang 的垃圾處理會自動回收;你們能夠具體嘗試一下
此文章完整代碼以下
// Enda <endachao@gmail.com>
package main
import "fmt"
func main() {
//數組是固定長度與容量,而且具備相同類型的一組值
//此定義的數組長度爲 5 ,那麼容量也會固定爲 5
arr := [5]int{0, 1, 2, 3, 4}
// 數組 p = 0xc00001c0f0,arr = [0 1 2 3 4],len = 5,cap = 5
fmt.Printf("數組 p = %p,arr = %+v,len = %d,cap = %d\n", &arr, arr, len(arr), cap(arr))
// 數組的索引都是從 0 開始的
// 0 1
fmt.Println(arr[0], arr[1])
// 切片能夠看作是一個可變長的數組
// 切片能夠看作是對數組的一個片斷的引用
// [1:3] 表示範圍從數組的索引 1 至 數組的索引 3,它是不包括 3 的,能夠簡單理解爲 index == 1 && index < 3
// 當切片生成後,索引默認也是從 0 開始, 切片索引是 [0,1] 對應着數組的索引是 [1,2]
arrSlice := arr[1:3]
// 切片 p = 0xc00000c060,arr = [1 2],len = 2,cap = 4
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice))
// 因爲切片是對底層數據的一個引用,因此修改底層數組會更改切片的值
arr[1] = 10
// 切片 p = 0xc00000c060,arr = [10 2],len = 2,cap = 4
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice))
// 一樣的道理,修改切片的值也會影響到底層數組
arrSlice[0] = 8
// 切片 p = 0xc00000c060,arr = [8 2],len = 2,cap = 4
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice))
// 數組 p = 0xc00001c0f0,arr = [0 8 2 3 4],len = 5,cap = 5
fmt.Printf("數組 p = %p,arr = %+v,len = %d,cap = %d\n", &arr, arr, len(arr), cap(arr))
// 對切片追加
// 追加前的切片索引是 [0,1] 對應着 數組的 [1,2]
// 在這裏追加了一位,那麼切片的索引是 [0,1,2] 數組對應的索引是 [1,2,3]
// 因此追加的值,也會修改數組的值
arrSlice = append(arrSlice, 11)
// 切片 p = 0xc00008a020,arr = [8 2 11],len = 3,cap = 4
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice))
// 數組 p = 0xc000090060,arr = [0 8 2 11 4],len = 5,cap = 5
fmt.Printf("數組 p = %p,arr = %+v,len = %d,cap = %d\n", &arr, arr, len(arr), cap(arr))
// 切片的容量爲何是 4
// 在建立切片時,咱們指定了對數組的 [1,3] 進行切片,這裏切出來的長度爲 2
// 切片在建立時,若是不指定容量,那麼容量會自動去計算
// 建立時計算容量的公式爲:建立時的長度 * 2
// 追加時,會先判斷長度夠不夠,若是夠則容量不變,若是不夠那麼判斷長度是否小於 1024 ,小於則容量 * 2,大於則 容量 * 1.25
// 當咱們切片的長度超過了原數組的長度
// 咱們能夠看到,數組的值並無被修改,按照咱們上一步講的來講,應該數組的最後一位會變爲 12,可是並無
// 這是一個很重要的概念,當咱們的切片容量大於底層數組容量時,會自動建立一個新的底層數組
arrSlice = append(arrSlice, 12, 13, 14)
// 切片 p = 0xc00000c060,arr = [8 2 11 12 13 14],len = 6,cap = 8
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice))
// 數組 p = 0xc00001c0f0,arr = [0 8 2 11 4],len = 5,cap = 5
fmt.Printf("數組 p = %p,arr = %+v,len = %d,cap = %d\n", &arr, arr, len(arr), cap(arr))
//當我再去修改切片的值時,並不會去操做咱們上面定義的數組了
arrSlice[0] = 18
// 切片 p = 0xc00008c020,arr = [18 2 11 12 13 14],len = 6,cap = 8
fmt.Printf("切片 p = %p,arr = %+v,len = %d,cap = %d\n", &arrSlice, arrSlice, len(arrSlice), cap(arrSlice))
// 數組 p = 0xc000092060,arr = [0 8 2 11 4],len = 5,cap = 5
fmt.Printf("數組 p = %p,arr = %+v,len = %d,cap = %d\n", &arr, arr, len(arr), cap(arr))
}
複製代碼