笨辦法學golang(四)

這是Go語言學習筆記的第四篇

Go語言學習筆記參考書籍「Go語言聖經」以及Go官方標準庫

數組

數組是指一系列同類型元素的集合。Go語言中,數組使用前必須指定長度,數組長度在定義以後就不可以更改

//數組的聲明
var arr1 [2] int
var arr2 [10] int
var arr3 [2][3]int		//二維數組
var arr4 [2]*int		//指針數組

//數組賦值
arr1[0] = 0
arr1[1] = 1
//指針數組賦值
v0 := 1
v1 := 2
arr4[0] = &v0
arr4[1] = &v1
//上述賦值適應於數組元素較少時,當數組元素較多,可以用for循環來處理
for i:=0; i<2; i++ {
    for j:=0; j<3; j++ {
        arr3[i][j] = i + j
    }
} 
//數組初始化
var arr5 = [5]float32{1.0, 2.0, 3.4, 5.6, 7.8}
arr6 := [2]int{0,1}
//[]中的數組可以忽略,編譯器會根據元素個數來設置
var arr7 = [...]string{"first name", "second name", "third name"}

可以使用內置函數len(arry)來獲取數組長度,如果想訪問數組元素,一般使用數組下標。數組下標從0開始,len(array)-1表示最後一個元素。除此之外,還可以使用關鍵字range

for i, v := range array {
    fmt.Println("Array element[", i, "]=", v)
}
//range 具有兩個返回值,第一個返回元素的數組下標,第二個返回元素值

需要特別注意,在Go語言中數組是一個值類型。值類型就是變量在賦值或作爲參數傳遞時會產生copy動作。因此,若函數的參數類型是數組,則函數調用時會發生數據copy,傳入函數的其實只是數組的一個副本,也就無法在函數內部更改數組內容。

func modifyArray(arr [5]int) {
    for i:=0; i<len(arr); i++ {
        arr[i] = i + 1
    }
    fmt.Println("In modifyArray(), array values: ", arr)
}

func main() {
    arr := [5]int{1,2,3,4,5}
    
    modifyArray(arr)
    
    fmt.Println("In main(), array values")
}

程序執行結果爲:

In modify Array(), array values: [3 4 5 6 7]
In main(), array values: [1 2 3 4 5]

那麼問題來了,如果想在函數內部修改數組內的數據怎麼辦呢?這時候則使用數組切片

數組切片

數組切片初看就像一個指向數組的指針,實際上它也有自己的數據結構,數組切片抽象爲3個變量:

  • 一個指向原生數組的指針
  • 數組切片中的元素個數
  • 數組切片已分配的存儲空間

基於數組,數組切片添加了一系列管理功能,可以隨時動態擴展存儲空間,並且可以被隨意傳遞而不會導致管理的元素被重複複製。

創建數組切片

創建數組切片有兩種方式,基於數組(數組切片)和直接創建(使用內置函數make())。我們通過例子來看兩種創建方式:

arr := [10]int{1,2,3,4,5,6,7,8,9,10}
var slice0 [] = arr[:5]//從數組創建
//創建個數爲5,初始值爲0的切片
var slice1 := make([]int, 5)
//創建個數爲5,初始值爲0,並預留10個存儲空間的切片
var slice2 := make([]int, 5, 10)
//直接創建5個元素切片
var slice3 := []int{1,2,3,4,5}

從上面看出,Go語言使用array[first:last]方式來生成數組切片,例如下面幾種都是合法的:

//基於arr的所有元素創建數組切片
var mySlice = arr[:]
//基於arr的前5個元素創建
var mySlice = arr[:5]
//基於從第5個開始創建後面所有的數組切片
var mySlice = arr[5:]
//創建從第2個到第5個的數組切片
var mySlice = arr[2:5]
//甚至創建的數組切片元素可以超過原數組元素個數,只要不超過原數組的存儲能力(cap()返回的值),超出部分會填0
var mySlice = slice2[2:7] //slice2數組有5個元素,儲存能力爲10

動態擴展元素

數組的所有操作同樣適應於數組切片,例如len()獲取元素個數,range()快速遍歷:

數組切片還有一個重要的功能就是可動態增減元素。數組切片支持內置的cap()函數,返回數組切片分配空間的大小。看個例子:

func main() {
    mySlice := make([]int, 5, 10)
    
    fmt.Println("len(mySlice): ", len(mySlice))
    fmt.Println("cap(mySlice): ", cap(mySlice))
    
    //往mySlice元素後追加新元素,形成新數組切片
    mySlice = append(mySlice, 1,2,3)
    
    mySlice2 := []int{8,9,10}
    
    mySlice = append(mySlice, mySlice2...)
    /* 上面這行代碼mySlice2後面的三個點如果缺少,會編譯錯誤。*/
    /* 原因是append的函數定義從第二個參數起,都是可增加參數。*/
    /* mySlice的元素類型是init, 直接傳遞的mySlice2是數組切片,類型錯誤。*/
    /* 加上省略號即三個點相當於把mySlice2包含的所有元素打散後傳入 */
    /* 相當於 mySlice = append(mySlice, 8,9,10) */
    fmt.Println("mySlice: ", mySlice)
    /*上面追加的元素超過了原來的10個元素容量,此時數組切片會重新自動處理存儲空間不足,自動分配一塊足夠大的內存*/
    
}

內容複製

slice1 := []int{1,2,3,4,5}
slice2 := []int{5,4,3}

copy(slice2, slice1) 	//只複製slice1的前三個元素
copy(slice1, slice2)	//只複製slice2的3個元素到slice1的前三個位置

數組切片支持內置函數copy(), 用於將內容在數組切片之間複製。上面的例子表明:如果兩個數組切片不一樣大,就會按照其中較小的數組切片的元素個數進行復制。

map

map是一堆鍵值對的未排序集合。先看一個例子:

//定義一個struct
type bookInfo struct {
    ID string
    Name string
    Price string
}
func main() {
    var bookDB map[string] bookInfo
    bookDB = make(map[string] bookInfo)
    
    //插入數據
    bookDB["1"] = bookInfo{"1", "Harry Potter", "$20"}
    bookDB["123"] = bookInfo{"123", "Steve Jobs:A Biography","$12"}
    
    //在map中查找
    book, ok := bookDB["1234"]
    
    if ok {
        fmt.Println("find the book: ", book.Name, "the price is: ", book.Price)
    } else {
        fmt.Println("sorry, didn't find the book.")
    }
}

上面例子涉及到了map的聲明、初始化、賦值,查找。

變量聲明

第8行聲明瞭一個map, 其中變量名爲bookDB, map的鍵類型爲string, 存放的值類型爲bookInfo.

創建

用內置函數make()創建一個map,像第9行代碼。也可以在創建的時候指定map的存儲能力:

bookDB = make(map[string]bookInfo, 100), 同樣也可以在創建map的時候初始化:

bookDB = map[string]bookInfo{"1": bookInfo{"1", "Harry Potter", "$20"}}

刪除元素

使用內置函數delete()來刪除map中的元素。例如:delete(bookDB, "123"),如果“123”不存在,則什麼都不會發生,如果存在,則會刪除key爲“123”的value。

查找元素

go語言中查找map中值非常方便,代碼如下:

value, ok := bookInfo["123"]
if ok {
    //找到了,處理找到的value
}

本文中的代碼均整合上傳至github, 請參考源文件

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