一篇文章帶你瞭解 Go 語言基礎之切片補充

前言

Hey,大家好呀,我是星期八,這次咱們繼續學習 Go 基礎之切片補充扒。

make 疑雲

我們知道,可以通過 make 創建切片。

var names = make([]string,10,10)

這句話表示動態創建了一個切片,切片中的元素數量爲 10 個,切片的容量也爲 10 個。

你有疑惑嗎???

切片的數量和容量是什麼???

他倆什麼關係???

切片本質

其實切片,終究是一個存儲數據的一個東西,目前知道數組是可以存儲東西的。

其實切片本質,還是數組,只不過是 Go 幫助我們做了一些封裝,可以方便的對切片裏面的數據增刪改查

例如:

package main
import "fmt"
func main() {
    var names = make([]int 4 10)
    //int類型默認值是0
    fmt.Println(names len(names) cap(names)) //結果:[0 0 0 0] 4 10
}

理解圖。

沒錯,本質就是指向了一個長一點的數組。

但是這個數組是會自動擴容的,當**容量 (cap)**append 滿了之後,會自動擴容。

現在,我們就知道 make 裏面參數的意義了。

注意: 在 Go 中,推薦使用 make 創建切片,並且在創建時,需要考慮容量,儘可能不觸發容量自動擴容機制,提高性能。

爲什麼切片 append 之後,前面會有空格

在上一章中,大概有這樣一段代碼。

package main
import "fmt"
func main() {
    var names = make([]int510)
    names = append(names1123231)
    fmt.Println(names)//[0 0 0 0 0 11 23 231]
}

append 之後,前面會有很多 0,這是怎麼回事。

解釋:

在通過 make 創建切片時,第二個參數切片元素數量

上述代碼切片第二個參數是 5,表示在創建切片時,前 5 個就已經有值了,只不過是 int 默認值 0。

所以再 append 時,是再原有的基礎上,添加值的,直到 cap 滿了之後,觸發擴容機制。

如圖所示。

現在,清晰了吧?

那怎麼 append 時,從 0 開始呢???

這不是很簡單,直接讓第二個參數爲 0。

var names = make([]int,0,10)
//結果:[11 23 231]

如圖所示。

好了,這個,懂了吧,怎麼繼續哈。

爲什麼不推薦使用 var [] 類型方式創建切片

我們上述一直在提一個詞,自動擴容

我們來看這樣一段普通的代碼。

package main
import "fmt"
func main() {
    var names []int
    //地址:0x0,長度(len):0,容量(cap):0
    fmt.Printf("地址:%p,長度(len):%d,容量(cap):%d\n" names len(names) cap(names))
    names = append(names 1 2 3)
    //地址:0xc000010380,長度(len):3,容量(cap):4
    fmt.Printf("地址:%p,長度(len):%d,容量(cap):%d\n" names len(names) cap(names))
}

雖然按照這種方法,使用 append 動態添加是沒問題的。

在不使用 make 聲明數組時,lencap 都是 0,並且地址也是一個值。

通過 append 之後,可以明顯看到,地址發生了改變,因爲又重新申請了數組,切片重新指向新的數組。

lencap 也發生了變化。

copy 複製切片

package main
import "fmt"
func main() {
    var names1 = make([]string 0 10)
    names1 = append(names1 "張三")
    names1 = append(names1 "李四")
    var names2 = names1         //將names1賦值到names2
    fmt.Println(names1 names2) //[張三 李四] [張三 李四]
    names1[0] = "張三666"//修改names下標爲0的值爲 張三666
    fmt.Println(names1 names2) //[張三666 李四] [張三666 李四]
    //爲什麼修改names1的值,會影響names2的值????
}

爲什麼修改 names1 的值,會影響 names2 的值???

這個,就又要回到內存分佈圖了,如圖所示。

我們說過很多次,不管是打印,還是賦值等操作,只會操作上面存儲的

names2=names1時,只會把names1棧上面的地址,給names2

但是存的時堆上面的地址,終究還是指向了同一個堆。

所以修改names1時,names2也修改了。

那如果不想出現上述問題怎麼辦???

解決辦法: 使用 copy

package main
import "fmt"
func main() {
    var names1 = make([]string 0 10)
    names1 = append(names1 "張三")
    names1 = append(names1 "李四")
    //定義一個names2切片用於接收,第二個參數要留空間,names1裏面又幾個元素,names2第二個參數也要是幾
    var names2 = make([]string 2 10)
    copy(names2 names1)//將names1的值,賦值到names2
    fmt.Println(names1 names2) //[張三 李四] [張三 李四]
    names1[0] = "張三666"//修改names下標爲0的值爲 張三666
    fmt.Println(names1 names2) //[張三666 李四] [張三 李四]
    fmt.Printf("names1地址:%p names2地址:%p\n"names1names2)
    //names1地址:0xc00009a0a0 names2地址:0xc00009a140
}

內存圖

自動擴容機制


非常抱歉,我不會。。。

總結


上述我們學習了 Go 基礎之切片補充。如果在操作過程中有任務問題,記得在下面的討論區留言,我們看到會第一時間解決問題。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/0h2kqwWJ7D_T6s8Eekw3Uw