Go基礎編程——切片slice

切片SIice
1、其 本 身 並 不 是 數 組 , 它 指 向底層數組
2、作 爲 變 長 數 組 的 替代 方 案 , 可 以 關 聯底層 數 組 的 局 部 或 全 部
3、爲 引 用 類 型
4、可 以 直 接 創 建 或從底層 數 組 獲 取 生 成
5、使 用 len() 獲 取 元 個 數,cap() 獲 取 容 量
6、一 般 使 用 make() 創 建
7、如 果 多 個Slice 指 向 相 同 底 叟 組 , 其 中 一 個 的 值 改 變 會 影 響 全 部
8、make(()T, Jen, cap)
其 中 ( ap 可 以 省 略 , 則和len 的 值 相 同
len 表 示 存儲的 元素個 數 ,cap表示容量
一個Slice的令名如下

var a []int

使用切片Slice截取數組的使用案例:

a :=[10]int{1,2,3,4,5,6,7,8,9,10}
fmt.Println(a)
s:=a[5:10]
fmt.Println(s)

運行結果如下:

[1 2 3 4 5 6 7 8 9 10]
[6 7 8 9 10]

值得注意的是——[5:10]包含起始端,不包含終止端。也就是數學上常說的左閉右開。
其實還有兩種方法可以實現把後面的數據全部截取

s:=a[5:]
s:=a[5:len(a)]

其實後一種方法等價於前一種,在比較好的編輯器上會提示
也就是說len(a)在這裏屬於多餘的索引。
同樣去前5個的方法:

s:=a[:5]

使用make()函數聲明Slice的方法

s1:=make([]int,3,10)

關於第一個參數3是初始化爲3個int類型的數據,容量是10個,當超出10的時候,Go語言機制中,容量翻倍成20,當達到21個時超出20個了,容量會繼續翻倍成爲40個,這些都是Go語言底層的機制實現的。這裏記住一點計算機重新分配內存地址是一種效率比較低的行爲,儘量讓容量一次滿足條件。還有當我們不設置第三個參數10的時候,也是可以的,這時候默認的最大容量就是3個。

Slice與底層數組之間的關係
下邊實現截取Slice_a的方法

a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
sa:=a[2:5]
fmt.Println(a)
fmt.Println(string(sa))

截取Slice_b方法如下:

a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
sb:=a[3:5]
fmt.Println(a)
fmt.Println(string(sb))

Reslice
1、Reslice 時 索 引 以 被Slice的 片 爲 準
2、索 引 不 可 以 超 過 被 slice 的 切 片 的 容 量 cap() 值
3、索 引 越 界 不 會 導 致 底 層 數 組 的 重 新 分 配 而 是 引 發錯誤
Append(重點)
1、可 以 在Slice尾 部 追 加 元 素
2、可 以 將 一 個 slice 追加 在 另 一 個slice 尾 部
3、如 果 最 終 長 度 未 超 過 追 加 到 Slice 的 容 量 則 返 回 原 始Slice
4、如 果 超 過 追 加 到 的Slice的 容 量 則 將 重 新分配數組並拷貝原 始 數 據
Copy
以下程序實現Reslice:

a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
sa:=a[2:5]
sb:=sa[1:3]
fmt.Println(a)
fmt.Println(string(sa))
fmt.Println(string(sb))

string(sb)運行結果
依舊是de,這就是Reslice
這裏引出一個之前對於Slice理解的一個誤區,看下邊程序以及運行結果:

sb:=sa[3:5]

運行結果是:

fg

這裏會有些誤解認爲sa只包含cde三個元素,怎麼會再次截取的時候會超出這三個呢,用程序來幫助理解是最好的辦法。

fmt.Println(len(sa),cap(sa))

運行結果是

3 9

就知道它的容量是9個,長度是3個。只是sa包含cde三個而已,Slice指向的是個連續的內存塊。

a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
sa:=a[2:5]
sb:=sa[3:11]
fmt.Println(a)
fmt.Println(len(sa),cap(sa))
fmt.Println(string(sa))
fmt.Println(string(sb))

運行結果:

panic: runtime error: slice bounds out of range

就報錯了,說超出容量了。由前邊的cap(sa)我們知道,最大容量是9個,這裏就要求把程序中的[3:11]改爲[3:9]

接下來是這節的重點,使用append()函數在Slice後面追加元素

s1:=make([]int,3,5)
fmt.Printf("%v,%p\n",s1,s1)
s1=append(s1,1,2,1,3)
fmt.Printf("%v,%p\n",s1,s1)

運行結果

0xc042066030
[0 0 0 1 2 1 3],0xc04206e0a0

添加之後顯示它的值和內存地址,可以看內存地址是不一樣的,值不一樣,這裏的內存地址不一樣的原因是,原來的最大容量5個,初始值的個數是3個在添加4個之後,最大容量翻倍變成10個。這時候的內存地址肯定不一樣,因爲Go語言的底層機制重新分配了一些內存給它。
想內存地址一樣,

s1:=make([]int,3,10)

這時候的運行結果如下

[0 0 0],0xc04206e0a0
[0 0 0 1 2 1 3],0xc04206e0a0

內存地址變成一樣了。
接下來說一個重點,當兩個切片共享同一個元素(共同指向同一個元素)時,只要其中一個切片改變這個元素,另外一個切片也會隨着改變。
看如下程序以及運行結果:

a:=[]int{1,2,3,4,5,6,7}

s1:=a[2:5]
s2:=a[0:3]
   fmt.Println(a,s1,s2)
s1[0]=9
fmt.Println(a,s1,s2)

運行結果

[1 2 3 4 5 6 7] [3 4 5] [1 2 3]
[1 2 9 4 5 6 7] [9 4 5] [1 2 9]

當然也把原始的數組改變了。這裏還有要注意的地方就是使用append改變s2時,當append()後超出原有的容量,Go語言的底層機制會給s2重新分配內存地址,它就不是原來的地址,這時候s1[0]=9對於s2來說是不影響的。看程序如下,以及它的運行結果就可以解釋這個了,這是我們使用append時特別注意的地方。

a:=[]int{1,2,3,4,5,6,7}

s1:=a[2:5]
s2:=a[0:3]
   fmt.Println(a,s1,s2)
   s2=append(s2,55,55,55,55,55,55,55,55,55,55,55,55)
s1[0]=9
fmt.Println(a,s1,s2)

運行結果如下

[1 2 3 4 5 6 7] [3 4 5] [1 2 3]
[1 2 9 4 5 6 7] [9 4 5] [1 2 3 55 55 55 55 55 55 55 55 55 55 55 55]

可以看到原來s2的3沒有被改變,這裏s2的3已經不是和s1指向同一塊地址了,所以沒法改變它,用程序輸出s1和s2指向的內存看看就知道了。

fmt.Printf("%p,%p\n",s1,s2)

運行結果如下

0xc042070050,0xc042072080

最後談談數組的copy函數

s1:=[]int{1,2,3,4,5,6}
s2:=[]int{7,8,9}
copy(s1,s2)
fmt.Println(s1)

運行結果

[7 8 9 4 5 6]

反過來s1複製到s2中

copy(s2,s1)
fmt.Println(s2)

運行結果是

[1 2 3]

容量長的切片複製到容量短的切片是,以容量短的爲準,換句話說以容器爲準。
再說說值複製一部分是如何實現的?
假如只複製s1中的4,5兩個元素到s2中

copy(s2,s1[3:5])
fmt.Println(s2)

運行結果

[4 5 9]

同樣複製的時候在容器中默認從下標爲0的位置開始放置複製過來的元素,當然也可以制定它放置的具體位置,比如上例中的複製元素4,5我想把它們放置在第二個和第三個位置,操作如下:

copy(s2[1:3],s1[3:5])

運行結果:

[7 4 5]

這樣就實現了想要的。
思考以下問題:
如何將一個Slice指向一個完整的底層數組,而不是部分底層數組?
接下來我就是來實現它:

s1:=[]int{1,2,3,4,5,6}
s2:=[]int{7,8,9}
      copy(s2[1:3],s1[3:5])
      s3:=s1[0:]
fmt.Println(s2)
fmt.Println(s3)

其中s3就實現了上述題目的要求。
當然也可以使用

s3:=s1[0:5]
s3:=s1[0:]
s3:=s1[:]

這三種方式完成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章