Go語言4-數組、切片及map

1、數組
數組長度定義後不可修改,通過內置函數len()來獲取數組元素個數

1)類型
    //長度爲32的byte數組,每個元素爲一個字節
    [32]byte

    //長度爲2*N的複雜類型數組
    [2*N] struct{x,y int32}

    //長度100的指針數組
    [100]*float64

    //二維數組,等同於[2]([3]int)
    [2][3]int

    //三維數組
    [2][2][2]float64
2)定義
    //定義一個長度爲5的數組,默認會使用int類型的零值(0)進行初始化
    arr := [5]int{}

    //與上面一句作用一樣
    var arr [5]int = [5]int{}

    //定義一個長度爲5的數組,其中arr[0]將被初始化爲1,其餘依舊是0
    arr := [5]int{1}

    //定義一個長度爲5的數組,其中arr[0]、arr[4]將被初始化爲1,其餘依舊是0
    arr := [5]int{0:1,4:1}

    //定義一個長度爲5的數組,默認會使用int類型的零值(0)進行初始化
    arr := new([5]int)

    //定義並初始化一個數組,這裏會自動推斷數組長度([...]起的作用),這裏需要跟後面切片定義的不同(沒有...)
    arr := [...]int{1, 2, 3, 4, 5}

    //定義並初始化一個數組,並且會自動推斷長度爲5,arr[4]將被初始化爲1,其餘依舊是0
    arr := [...]int{4:5}
3)遍歷
    //與其它編程語言類型的遍歷方式
    //獲取數組arr的長度
    lenth := len(arr)             
    for i := 0; i < lenth; i++ {  
         //使用數組索引方式遍歷數組
         fmt.Print(arr[i], " ")
    }
    //使用range方式遍歷數組,range有兩個返回值,1爲索引,2爲值
    for i, v := range arr {
         fmt.Print("[",i,"]=",v, " ")
    }
4)比較操作
在兩個數據是同一類型(長度及元素類型)時,可以使用==與!=對兩個數組進行比較,但不能使用<或>。
注:Go語言中數組是一個值類型,所有值類型變量在賦值和作爲參數傳遞時都將產生一次複製動作,
    傳入函數中的數組僅是該數組的一個副本,因此就無法對其進行修改,如果此時的數組較大時,
    將會降低程序的效率,關於這種場景的解決,下面的切片會進行講解。

2、切片

在上面我們提到數組兩個特點:
1、數據長度在定義後無法再次進行修改;
2、數據是值類型,每次傳遞都將產生一個副本;
而Slice(切片)正是爲解決以上兩個問題而存在。
從表象看,切片是一個指向原始數組的指針,但實際上,切片擁有自己的數據結構
1、一個指向原生數組的指針
2、數組切片中的元素個數
3、數組切片已分配的存儲空間
這裏需要區分兩個概念,
長度:切片已使用的大小,從切片頭開始算起,使用內置函數len()獲取
容量:切片允許使用的大小,從切片頭開始算起,至底層數組末尾,使用內置函數cap()獲取,
      當切片長度超過容量時,會重新分配一個原容量兩倍的容間,並將值複製過去,與Java
      中的ArrayList有點類似,要注意擴容後的內存地址與原內存地址不一樣。

1)定義
    //此處先定義一個數組
    arr      := [5]int{}
    //基於上面定義的數據定義一個指向arr索引值在[0,5)範圍(左開右閉)的切片
    //這裏的[m,n]還可以有多種寫法,如[:5]表示[0,5),[1:]表示[1,len(arr)),[:]表示[0,len(arr))
    arrSlice := arr[0:5]

    //定義一個長度爲5,容量也爲5的切片,這裏要注意跟上面數組定義的差別,數組定義時中括號中有...
    arrSlice := []int{1,2,3,4,5}

    //定義一個長度爲5,容量也爲5的切片
    mySlice  := make([]int,5)

    //定義一個長度爲5,容量爲10的切片
    mySlice  := make([]int,5,10)

    //在切片上再切片,這種情況又叫做reslice,這裏的[m:n]必須滿足0<=m<n<=cap(mySlice)-m
    mySlice2 := mySlice[:]
在reslice的情況下,有很多地方需要注意,因爲原slice與reslice實際底層使用的是同一塊內存
空間,當兩個的長度都在底層數組的長度內時,兩者共享的都是同一塊容間,當有一個超過之後,
這種情況將會被打破。如下面的代碼所示:
    mySlice    := make([]int,5,6)
    //即mySlice[1]對應mySlice2[1],以此類推
    mySlice2   := mySlice[1:]
    //這裏相當於同時也對mySlice2[0]的值進行了修改
    mySlice[1]  = 10
    //append爲內置函數,表示給切片追加值,mySlice長度增加了,但mySlice2長度依舊不變
    mySlice     = append(mySlice,1)
    //這裏將會把mySlice[5]的值覆蓋爲2,即覆蓋上一句代碼的值
    mySlice2    = append(mySlice2,2)
    //經過上面代碼,已經用完所有空間,再添加值時,將會發生空間分配
    mySlice2 = append(mySlice2, 7)
    //這裏僅改變了mySlice2[0],而mySlice[1]不變
    mySlice2[0] = -1
2)遍歷與數組遍歷一樣,這裏就不復述了

3)切片的增減
    //在切片末尾添加值 1 ,如果超過容量,會導致重新分配容間,容量會是原容量的2倍
    mySlice = append(mySlice,1)

    //在切片末尾同是添加多個值
    mySlice = append(mySlice,1,2,3)

    //在切片末尾追加一個數組,這裏的"..."是必需的,否則會編譯錯誤,表示把數組打散後傳入
    mySlice = append(mySlice,arr...)

    //在切片末尾添加另一個切片,這裏mySlice2後的[:]被省略了
    mySlice = append(mySlice,mySlice2...)

    //切片的減,這裏表示刪除掉了mySlice[1],切片的長度減小,但容量不變
    mySlice = append(mySlice[:1],mySlice[2:]...)

    //切片的減,如果是要刪除切片末尾的話,則可以使用reslice的方式爲實現
    mySlice = mySlice[0 : len(mySlice)-1]
4)內容複製
用於將內容從一個數組切片複製到另一個數組切片。
如果兩個切片不一樣大,將以較小切片的元素個數進行復制
    //這裏要注意順序,與Java的那種前者from後者to相反
    copy(targetSlice,sourceSlice)

3、map
未排序的鍵值對集合,系統直接內置,無需引入其它包

1)聲明
var 變量名 map[鍵類型]值類型
    var myMap map[int]string
2)創建
    //創建一個key爲int,值爲string的map,myMap需要先聲明
    myMap = make(map[int]string)

    //聲明+創建
    myMap := make(map[int]string)

    //創建一個容量爲100的map
    myMap = make(map[int]string,100)

    //聲明+創建
    myMap = map[int]string{}

    //聲明+創建+初始化
    myMap = map[int]string{1: "1"}
3)元素賦值、刪除、查找
    //增加或修改key=123對應的元素值爲字符型"123"
    myMap[123] = "123"

    //刪除key=123對應的元素
    delete(myMap,123)

    //查找key=123對應的元素,該操作有兩個返回值,多返回值知識點將在函數相關內容說到,
    //返回值1爲對應的值,返回值2爲是否包含該key
    v, ok := myMap[123]

本文介紹了編程中最常用的兩種數據結構,數組及map,同時介紹了一種可伸縮的”數組”又可以看作爲一個數組指針–切片,數組與切片有太多相似的地方,但同時又存在差異,所以做爲新手要特別注意。

無聞(unknow)《Go編程基礎》
許式偉的 《Go語言編程》

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