1. 程式人生 > >【Go】詳解Go的陣列與切片

【Go】詳解Go的陣列與切片

11. Go 陣列
陣列是指包含同一型別元素的集合,Go不允許陣列混合不同的資料型別
11.1 陣列的詭異宣告語法

     var arr [3] int  //宣告但不初始化,Go會根據資料型別賦予預設初始化值0  // [0,0,0]
     var arr = [3]int{5,8,9}  //宣告並且初始化  // [5,8,9]
     var arr = [...]int{5,8,9}  //宣告並且初始化,忽略陣列元素個數,Go根據{}內元素個數自動賦予陣列長度  //[5,8,9]
     // 使用:=簡潔大法
     arr := [3]int{12}  //自動將剩下的未初始化的值賦予預設值0   //[12,0,0]
     a := [...]int{12, 78, 50}


11.2 陣列長度 len(arr)
11.3 使用range遍歷陣列

for index,value := range arr {
  ...
}
for _,value := range arr {  //忽略陣列下標
  ...
}


11.4 多維陣列

 arr := [3][2]string{
  {"A","B"},
  {"a","b"},
  {"1","2"},
 }


12. Go 切片
因為在Go中陣列是定長的,所以不定長的切片比陣列更常用。切片本身不擁有任何資料,是對現有陣列的引用。
切片宣告與陣列型別,區別在於一個有長度一個沒有長度。
12.1 切片宣告
  12.1.1  

var myslice []int  //宣告切片但不賦值  myslice=nil

  12.1.2  

myslice := []int{6,7,8} 
 //與陣列宣告類似,但不寫明長度。
//此時創造了陣列[6,7,8]並返回了myslice對該陣列的引用  len(myslice)為3 cap(mysplice)為3


12.2 對現有陣列的引用,假定現有陣列 arr := [...]int{0,1,2,3,4,5,6,8}

//12.2.1  
var myslice [] int = arr[1:4]  //代表擷取陣列arr下標1至4-1  [1,2,3]
//12.2.2  
myslice := arr[1:4]
//12.2.2 
myslice := arr[:] //表示對arr陣列的全部引用


 因為切片是對現有陣列的引用,所以改變切片,被引用的陣列也會改變

12.3

   len(myslice)  //表示切片的長度 例如arr[1:4] 返回值為3
   cap(myslice) //表示切片的容量 例如arr[1:4]  返回值為 len(arr) - startIndex // 7

12.4 使用make建立切片
func make([]T,len,cap) []T {...}

myslice := make([]int,5,5)  //[0,0,0,0,0] cap引數可選,預設為len

12.5 追加切片元素
func append(s[]T,x...T) []T {...}

myslice = append(myslice,10)

12.6 多維切片:與多維陣列類似,只要不宣告長度即可

mysplice := [][]string{
 {"A","B"},
 {"a","b"},
 {"1","2"},
}
//如何迴圈輸出多維切片/多維陣列
for _, v1 := range mysplice {
    for _, v2 := range v1 {
        fmt.Printf("%s ", v2)
    }
    fmt.Printf("\n")
}

12.7 記憶體優化
參考連結:https://studygolang.com/articles/12121
切片持有對底層陣列的引用。只要切片在記憶體中,陣列就不能被垃圾回收。在記憶體管理方面,這是需要注意的。
讓我們假設我們有一個非常大的陣列,我們只想處理它的一小部分。然後,我們由這個陣列建立一個切片,並開始處理切片。
這裡需要重點注意的是,在切片引用時陣列仍然存在記憶體中。一種解決方法是使用 copy 函式 func copy(dst,src[]T)int 來生成一個切片的副本。這樣我們可以使用新的切片,原始陣列可以被垃圾回收。

package main

import (
    "fmt"
)

func countries() []string {
    countries := []string{"USA", "Singapore", "Germany", "India", "Australia"}
    neededCountries := countries[:len(countries)-2]
    countriesCpy := make([]string, len(neededCountries))
    copy(countriesCpy, neededCountries) //copies neededCountries to countriesCpy
    return countriesCpy
}
func main() {
    countriesNeeded := countries()
    fmt.Println(countriesNeeded)
}


12.8 將切片傳入可變引數函式中

func find (num int,nums ...int){
 ...
}
func main(){
  mysplice := []int{5,8,9}
  find(0,mysplice...)
}

tips:在函式體內對形參切片現有的元素進行改變,實參切片也會改變,但是對形參切片進行追加元素,實參切片無變化
Go語言的引數傳遞都是值傳遞。切片包含三部分:長度,容量,指向陣列的第n個元素的指標
當切片作為引數傳遞過去(注意是值傳遞),此時拷貝了一份切片副本(在函式體內使用的就是切片副本)。
然而不管是原切片還是切片副本,其內的元素是指標指向,指向同一個地址,所以我們對切片副本現有的元素做修改,原切片也會變化
但是我們對副本切片做修改,如append,並不會影響原切片