Go數組和切片你不知道的區別

開篇語

  • 數組和切片是兩種不一樣的數據結構,比較常見,在Go語言中同時存在,今天咱們就一塊兒來看看他們在使用方式上,原理上的一些區別?

數組

  • 在Go語言中,數組是一種具備相同類型固定大小的一種數據結構。golang

  • 咱們先來看看數組的使用,數組類型聲明時的方式是 []T ,前面的[]指定數組的大小,T指定數組的類型,以下咱們聲明瞭一下數組,數組的大小是3,在沒指定數組初始值時數組默認初始值是{0,0,0}數組

array1 := [3]int{}
//咱們能夠經過以下方式給數組賦值
array1[0] = 1
array1[1] = 2
array1[2] = 3
//下面這種也是數組聲明的一種方式,而且初始化數組的值爲{1,2}
array2 := [2]int {1,2}
  • 思考一下前面咱們array1賦值給array2對嗎?記住,這種方式是錯誤的,在Go語言中只有大小相等,類型相同的數組纔是同類型的數組,之間才能夠相互賦值,以下截圖,咱們能夠看見array1賦值給array2時編譯器報錯
array2 = array1

  • 看上面的圖,咱們再思考一個問題,咱們把array3 賦值給array2後,修改了array3下標爲0的值等於6,請問打印的結果是?這個問題考驗的是咱們把array3賦值給array2後,修改了array3的值,會對array2產生影響嗎?答案是不會,記住,在Go中,數組屬於基本類型,他們之間的賦值,傳遞是屬於值拷貝,一樣的,若是將數組做爲參數在函數間傳遞,也是屬於值拷貝
第一種結果:0,0,0;  4,5; 6,5
第二種結果:0,0,0;  6,5; 6,5
  • 數組的長度,咱們聲明瞭一個數組,那如何獲取數組的長度呢?經過len(array4)獲取數組的長度
array4 := [2]int {1,2}
l := len(array4)
fmt.Println(""l)
  • 多維數組的聲明,多爲數組能夠想象成就是多個一維數組,以下聲明瞭一個二維數組,表明有兩個一維數組,每一個一維數組的長度是2
array4 := [2][2]int{}
array6 := [2][2]int{{1,2},{3,4}}
  • 對數組的訪問和遍歷
//訪問數組中的元素
array4 := [2]int {1,2}
//訪問數組下標爲0處的值並打印
fmt.Println(array4[0])
//經過range遍歷數組,
//i表明數組的下標,
//v表明數組下標爲i處的值
for i,v := range array4{
    fmt.Println(i,v)
}    
array5 := [2][2]int{{1,2},{3,4}}
for i,tempArray := range array5{
    //此時tempArray是一維數組
    //再經過range 遍歷tempArrayy一維數組
    for j,v := range tempArray{
        fmt.Println(j,v)
    }
}

切片

  • 在Go語言中,切片是數組的一種高級運用,相對於數組,切片是一種更加方便,靈活,高效的數據結構。,切片並不存儲任何元素而只是對現有數組的引用(不是值拷貝,是指針)微信

  • 切片的聲明方式有如下幾種
  • 經過數組建立一個切片數據結構

array1 := [3]int{1,2,3}
//將數組下標從1處到下標2處的元素轉換爲一個切片(前閉後開)
slice1 := array1[1:2]
  • 直接聲明一個切片
//下面代碼直接出初始化一個切片 (這裏你們有個疑問,我無論怎麼看都以爲它是一個數組啊)
//記住,再go語言中,區別一個變量是數組仍是切片,就看有沒有定義長度
//有定義長度就是數組,如array1,沒定義就是切片 如slice2
//咱們也經過fmt.Println(reflect.TypeOf(array1),reflect.TypeOf(slice2))
//上面這代碼打印的結果是[3]int,[]int,能夠看到前者有長度,後者沒有
slice2 := []int{1,2,3}
  • 經過make函數建立一個切片,也是最經常使用的
//[]int,指定切片的類型,3是切片的長度,6是切片的容量
slice3 := make([]int,3,6)
  • 經過切片生成一個切片
//聲明一個切片
slice4 := []int {1,2,3,4,5,6}
//經過slice4建立一個切片,元素是slice4下標從0到1(不包含1)的元素
slice5 := slice4[0:1] 
//經過slice4建立一個切片,元素是slice4下標從0到末尾的元素
slice6 := slice4[1:] 
 //經過slice4建立一個切片,元素是slice4下標從0到3的元素
slice7 := slice4[:3]
  • 上面咱們介紹了切片的幾種常見構造方式,接下來咱們看看如何操做切片
slice3   := make([]int,3,6)
//給切片賦值
slice3[0] = 0
slice3[1] = 1
slice3[2] = 2
//經過len([]Type) cap([]Type)兩個函數查看切片的長度和容量
fmt.Println(len(slice3),cap(slice3))
結果:3,6
  • 思考一下咱們能給上面切片slice3下標爲3處賦值嗎 ? slice3[3] = 3,答案是不能的,雖然咱們定義了切片的長度是3,容量是6,但對切片的操做是以長度爲準的,若是已經賦值到最大長度了,怎麼辦呢?切片爲咱們提供了append([]Type, elems...Type)[]Type 方法向切片中追加元素 []Type表明傳入一個切片,elems表明追加的元素,能夠傳多個。
//想slice3 切片追加三個元素,返回一個新的切片
slice3 = append(slice3,3,4,5)
//此時再次查看切片的長度和容量
fmt.Println(len(slice3),cap(slice3))
結果: 6, 6 切片的長度和容量保持一致了
//思考一下,咱們再次append能給切片追加元素嗎? 確定能夠的,前面說過切片是可擴長的
slice3 = append(slice3,7,8,9)
//此時再次查看切片的長度和容量
fmt.Println(len(slice3),cap(slice3))
結果:9, 12
發現了什麼?在切片容量滿時,切片的擴容時翻倍的,也就是新的切片的容量時原切片的容量的2倍
  • 知道了切片的追加,長度,容量,那麼如何刪除切片裏的元素呢?若是你在看經過切片建立一個切片時思考過,你就知道如何刪除切片中的元素了
//咱們建立了一個切片,有四個元素,下標命名爲0,1,2,3
slice11 := []int{1,2,3,4} 
//假設咱們要刪除下標爲0的元素,這段代碼的含義是
建立一個空的切片 slice11[:0]
建立一個從下標1到末尾元素的切片 slice11[1:]
給空切片添加元素並返回一個新的切片
slice12 := append(slice11[:0],slice11[1:]...)
//同上咱們得出刪除下標爲i的元素的切片的公式時
sliceTemp := append(slice11[:i],slice[i+1:]...)
  • 下圖是切片刪除的一個過程

數組和切片的底層存儲

  • 咱們看下圖分析

  • 基於上圖咱們會發現,切片的底層就是數組,切片是經過指針的形式指向不一樣數組的位置從而造成不一樣的切片,切片對自己元素的修改,也會影響到數組和其它的切片。看下面代碼,你們猜一猜輸出結果
array11 := [5]int{1,2,3,4,5}
slice11 := array11[0:3]
slice11[0] = 10
sliceTemp := append(array11[:2],array11[3:]...)
slice11[0] = 11
fmt.Println(array11,slice11,sliceTemp)
//輸出結果:[11 2 4 5 5] [11 2 4] [11 2 4 5]

歡迎你們關注微信公衆號:「golang那點事」,更多精彩期待你的到來
app

相關文章
相關標籤/搜索