1. 程式人生 > >Go語言學習筆記(三) 集合型別

Go語言學習筆記(三) 集合型別

陣列

陣列中包含的每個資料被稱為陣列元素(element),一個數組包含的元素個數被稱為陣列的長度。

[32]byte // 長度為32的陣列,每個元素為一個位元組
[2*N] struct { x, y int32 } // 複雜型別陣列
[1000]*float64 // 指標陣列
[3][5]int // 二維陣列
[2][2][2]float64 // 等同於[2]([2]([2]float64))

元素訪問

for i := 0; i < len(array); i++ {
fmt.Println("Element", i, "of array is", array[i])
}
for i, v := range array {
fmt.Println("Array element[", i, "]=", v)
}

在Go語言中陣列是一個值型別(value type)

package main
import "fmt"
func modify(array [10]int) {
array[0] = 10 // 試圖修改陣列的第一個元素
fmt.Println("In modify(), array values:", array)
}
func main() {
array := [10]int{1,2,3,4,5} // 定義並初始化一個數組,未定義的元素為零值,即0
modify(array) // 傳遞給一個函式,並試圖在函式體內修改這個陣列內容
fmt.Println("In main(), array values:", array)
}
該程式的執行結果為:
In modify(), array values: [10 2 3 4 5 0 0 0 0 0]
In main(), array values: [1 2 3 4 5 0 0 0 0 0]

可以用指標的概念解決這個問題

package main
import "fmt"
func modify(array *[10]int) {//接收指標值
array[0] = 10 // 試圖修改陣列的第一個元素
fmt.Println("In modify(), array values:", array)
}
func main() {
array := [10]int{1,2,3,4,5} // 定義並初始化一個數組,未定義的元素為零值,即0
modify(&array) // 傳遞指標
fmt.Println("In main(), array values:", array)
}
該程式的執行結果為:
In modify(), array values: &[10 2 3 4 5 0 0 0 0 0]
In main(), array values: [10 2 3 4 5 0 0 0 0 0]

如果你使用多維陣列,有一些內容你必須錄入:

a := [2][2]int{ [2]int{1,2}, [2]int{3,4} }
a := [2][2]int{ [...]int{1,2}, [...]int{3,4} }//Go 會自動統計元素的個數。
a := [2][2]int{ {1,2}, {3,4} }

切片slice

slice 與array 接近,但是在新的元素加入的時候可以增加長度。slice 總是指向底層的一個array。slice 是一個指向array 的指標,這是其與array 不同的地方;slice 是引用型別,這意味著當賦值某個slice 到另外一個變數,兩個引用會指向同一個array。例如,如果一個函式需要一個slice 引數,在其內對slice 元素的修改也會體現在函式呼叫者中,這和傳遞底層的array 指標類似。

建立陣列切片

建立陣列切片的方法主要有兩種——基於陣列和直接建立。

基於陣列:

func main() {
// 先定義一個數組
var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 基於陣列建立一個數組切片
var mySlice []int = myArray[:5]
fmt.Println("Elements of myArray: ")
for _, v := range myArray {
fmt.Print(v, " ")
}
fmt.Println("\nElements of mySlice: ")
for _, v := range mySlice {
fmt.Print(v, " ")
}
fmt.Println()
}
執行結果為:
Elements of myArray:
1 2 3 4 5 6 7 8 9 10
Elements of mySlice:
1 2 3 4 5

Go語言支援用myArray[first:last]這樣的方式來基於陣列生成一個數組切片

基於myArray的所有元素建立陣列切片:
mySlice = myArray[:]
基於myArray的前5個元素建立陣列切片:
mySlice = myArray[:5]
基於從第5個元素開始的所有元素建立陣列切片:
mySlice = myArray[5:]

直接建立:
並非一定要事先準備一個數組才能建立陣列切片。Go語言提供的內建函式make()可以用於靈活地建立陣列切片。當然,事實上還會有一個匿名陣列被創建出來,只是不需要我們來操心而已。

建立一個初始元素個數為5的陣列切片,元素初始值為0:
mySlice1 := make([]int, 5)
建立一個初始元素個數為5的陣列切片,元素初始值為0,並預留10個元素的儲存空間:
mySlice2 := make([]int, 5, 10)
直接建立並初始化包含5個元素的陣列切片:
mySlice3 := []int{1, 2, 3, 4, 5}
直接建立並初始化包含4個元素的陣列切片:
mySlice3 := []interface{}{3,"str", []int{3,4},func() {fmt.Println()}}

 

 

len() 和 cap()函式

因為切片(Slice)是陣列上的抽象。它實際上使用陣列作為底層結構體.len()函式返回切片中存在的元素數量,其中cap()函式返回切片(Slice)的容量(大小),即可容納多少個元素。以下是解釋切片(Slice)的用法的示例:

package main
import "fmt"
func main() {
   var numbers = make([]int,3,5)
   printSlice(numbers)
}
func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
當上述程式碼編譯和執行時,它產生以下結果:
len=3 cap=5 slice=[0 0 0]

append()和copy()函式

切片(Slice)允許使用append()函式增加切片的容量(大小)。使用copy()函式,將源切片的內容複製到目標切片。以下是示例:

package main

import "fmt"

func main() {
   var numbers []int
   printSlice(numbers)

   /* append allows nil slice */
   numbers = append(numbers, 0)
   printSlice(numbers)

   /* add one element to slice*/
   numbers = append(numbers, 1)
   printSlice(numbers)

   /* add more than one element at a time*/
   numbers = append(numbers, 2,3,4)
   printSlice(numbers)

   /* create a slice numbers1 with double the capacity of earlier slice*/
   numbers1 := make([]int, len(numbers), (cap(numbers))*2)

   /* copy content of numbers to numbers1 */
   copy(numbers1,numbers)
   printSlice(numbers1)   
}

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
Go
當上述程式碼編譯和執行時,它產生以下結果:

len=0 cap=0 slice=[]
len=1 cap=2 slice=[0]
len=2 cap=2 slice=[0 1]
len=5 cap=8 slice=[0 1 2 3 4]
len=5 cap=16 slice=[0 1 2 3 4]

字典map

map 可以認為是一個用字串做索引的陣列(在其最簡單的形式下)。下面定義了map 型別,用於將string(月的縮寫)轉換為int – 那個月的天數。一般定義map 的方法是:map[<from type>]<to type>

monthdays := map[string]int{
"Jan": 31, "Feb": 28, "Mar": 31,
"Apr": 30, "May": 31, "Jun": 30,
"Jul": 31, "Aug": 31, "Sep": 30,
"Oct": 31, "Nov": 30, "Dec": 31,   //逗號是必須的
}

留意,當只需要宣告一個map 的時候,使用make 的形式:

monthdays := make(map[string]int)

當在map 中索引(搜尋)時,使用方括號。例如打印出12 月的天數:

fmt.Printf("%d\n",monthdays["Dec"])

當對array、slice、string 或者map 迴圈遍歷的時候,range 會幫助你,每次呼叫,它都會返回一個鍵和對應的值。

year := 0
for _, days := range monthdays {   鍵沒有使用,因此用_, days
year += days
}
fmt.Printf("Numbers of days in a year:%d\n", year)

向map 增加元素,可以這樣做:

monthdays["Undecim"] = 30   //新增一個月
monthdays["Feb"] = 29   //年時重寫這個元素

檢查元素是否存在,可以使用下面的方式:

var value int
var present bool
value, present =monthdays["Jan"]   //如果存在,present 則有值true

或者更接近Go 的方式

v, ok := monthdays["Jan"]   //“逗號ok”形式

也可以從map 中移除元素:

delete(monthdays, "Mar")   //刪除"Mar" 

通常來說語句delete(m, x) 會刪除map 中由m[x] 建立的例項。