(三)go的高階資料與結構型別
阿新 • • 發佈:2018-11-10
1.go的陣列與切片
package main import "fmt" /* 陣列是go語言程式設計中最常用的結構之一。顧名思義,陣列就是一系列同一型別資料的集合。 陣列中包含的每一個元素成為陣列元素(element),一個數組包含的元素的個數被稱為陣列長度 */ func main(){ var arr1 [5]int //宣告一個數組arr1,裡面可以存五個int型別的資料 fmt.Println(arr1) //[0 0 0 0 0],沒有初始化,go語言也不會報錯,會預設初始化為零值 //還可以修改 arr1[1] = 100 //修改陣列會直接在陣列本身上修改,但是不可以越界,不可以arr[7] = 100 fmt.Println(arr1) //[0 100 0 0 0] var arr2 = [5]int{1,2,3} //初始化只給三個值,那麼剩餘的會自動用零值填充 fmt.Println(arr2) //1 2 3 0 0] //如果我們不確定有多少個元素,或者我們不想數,該怎麼辦呢? var arr3 = [...]int{15,112,4,2} //使用...表示讓編譯器幫我們數有多少個元素,而且我們輸入幾個元素,就代表陣列的長度是多少 fmt.Println(arr3) //[15 112 4 2] //我們在初始化陣列的時候,還可以指定某幾個元素的值 //比方說我初始化長度為10的陣列,但指定索引為2的值是10,索引為8的元素是25,怎麼做呢? var arr4 = [10]int{2:10,8:25} fmt.Println(arr4) //[0 0 10 0 0 0 0 0 25 0] //如果我這裡沒有指定陣列長度,而是用...代替的話,那麼arr4的長度就為9 //因為我們這裡指定索引為8的元素是25,那麼編譯器就將陣列的最大索引定位8,所以是9個元素 //如果我們初始化 var arr4 = [...]{100: 20}, 那麼長度就是101 //因為我們既然指定了索引為100的值是20,那麼陣列至少有101個,而我們又是...,那麼go編譯器就直接預設生成長度為101的陣列 }
package main import "fmt" /* 在go中,切片是長度可變,容量固定的相同元素的數列。 go切片本質上是一個數組,容量固定是因為陣列的容量是固定的,切片的容量就是隱藏陣列的長度,切片的長度可變是指在陣列的長度範圍內可變 怎麼理解呢?切片可以看做指向陣列的指標,切片具有長度和容量 長度:切片元素的個數 容量:切片底層陣列的個數 切片的定義方式和陣列類似,不同的是[]裡面不需要任何東西 */ func main() { var slice1= []int{1, 2, 3, 4, 5, 6} //len表示切片的長度,cap表示切片的容量也就是底層陣列的長度 //不過這裡貌似沒有底層陣列,就把[6]int{1,2,3,4,5,6]看成底層陣列就可以了 fmt.Println(len(slice1), cap(slice1)) // 6 6 ,此時切片的長度和容量都是6 //我們初始化一個數組 var arr= [...]int{1, 2, 3, 4, 5, 6} var slice2= arr[:] //此時的arr就是slice2的底層陣列,可以把slice2看成是arr的view,通過切片來看底層的陣列 fmt.Println(len(slice2), cap(slice2)) // 6 6 //我們修改一下slice2 slice2[1] = 100 fmt.Println(arr) //[1 100 3 4 5 6] //當我們修改了slice2,發現arr的值也被改變了,說明切片是一個指向陣列的指標,修改切片等於修改陣列 //我們再來看一個有趣的例子 s1 := arr[1:3] fmt.Println(s1) //[100 3] //這裡的s1裡面只有兩個元素,但是我們取了1: 4 s2 := s1[1:4] fmt.Println(s2) //[3 4 5],這裡列印了3, 4, 5 //為什麼會發生這種現象 /* arr: 1 100 3 4 5 6 s1: 100 3 s2: 3 4 5 上面說了,切片是底層陣列的一個view,s1和s2都是view這個arr,是可以擴充套件的 可以向後看,但是不可以向前看,s2向前最多也就只能看到100,不可能看到100前面的1, 如果指定s1[1:8]那麼顯然就不行了,因為底層陣列只有6個元素,索引最大的才是5,而且s1[0]相當於arr[1],所以s1最多就是s1[:5] */ var arr2 = [5]int{1,2,3,4,5} var s3 = arr2[:3] fmt.Println(s3) //[1 2 3] //同理我們這裡列印s3[0: 5]也沒有問題,因為s3view底層陣列arr2,但如果是s3[4]就會越界,因為切片沒有索引為4的元素 fmt.Println(s3[0: 5]) //[1 2 3 4 5] //之前不說數切片的長度在陣列長度的範圍內是可變的嗎?怎麼變呢?可以使用append s3 = append(s3, 500)//我往s3的末尾新增一個500 fmt.Println(s3) //[1 2 3 500] fmt.Println(arr2) // [1 2 3 500 5] //首先s3很好理解,但是arr2為什麼變了。 //我們往s3的末尾新增一個500,s3又view這個arr2,等價於s3=arr2[:4],s3[3]=500 //而且append會有一個返回值,而且可以一次性新增多個元素,append(s, element1, element2......) //如果我想把一個切片裡的元素全部新增進去該怎麼辦?在python中可以使用*,在go中可以使用... append_slice := []int{100,200} s3 = append(s3, append_slice...) fmt.Println(s3) //[1 2 3 500 100 200],此時我們動態新增已經超過了底層陣列的容量 //我們來看看底層陣列 fmt.Println(arr2) //[1 2 3 500 5] //底層陣列沒有變化,因為我們一次性新增兩個元素,已經超過了底層陣列的長度。 //此時go會自動分配一個更大的陣列,讓s3去view,換句話說此時的s3已經不再view arr2,至於s3view的陣列在什麼地方,這個就不得而知了。 //此時再改變s3 s3[0] = 123456 fmt.Println(arr2) //[1 2 3 500 5] //會發現arr2依舊沒有改變,因為s3已經不再看arr2這個陣列了,因此s3改變只會影響那個不知道在什麼地方的陣列,不會影響arr2 //建立切片,還有另一種方式,使用make([]type, len, cap) s4 := make([]int, 4) //如果不寫cap,那麼預設和len一致 fmt.Println(s4) // [0 0 0 0] fmt.Println(len(s4),cap(s4)) //4 4 s4 = append(s4, 1, 2) fmt.Println(len(s4),cap(s4)) //6 8 s4 = append(s4,3,4) fmt.Println(len(s4),cap(s4)) //8 8 s4 = append(s4, 4) fmt.Println(len(s4),cap(s4)) //9 16 //可以看到一旦滿了,就會擴大一倍 //那麼如何遍歷陣列或者切片呢?使用for迴圈 girls := []string{"古明地覺", "霧雨魔理沙", "芙蘭朵露斯卡雷特"} for i:=0;i<len(girls);i++{ fmt.Println(girls[i]) /* 古明地覺 霧雨魔理沙 芙蘭朵露斯卡雷特 */ } for _,name := range girls{ fmt.Println(name) /* 古明地覺 霧雨魔理沙 芙蘭朵露斯卡雷特 */ } }