這是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, 請參考源文件