笨辦法學(xué)golang(四)

這是Go語言學(xué)習(xí)筆記的第四篇

Go語言學(xué)習(xí)筆記參考書籍「Go語言圣經(jīng)」以及Go官方標準庫

數(shù)組

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

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

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

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

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

需要特別注意,在Go語言中數(shù)組是一個值類型。值類型就是變量在賦值或作為參數(shù)傳遞時會產(chǎn)生copy動作。因此,若函數(shù)的參數(shù)類型是數(shù)組,則函數(shù)調(diào)用時會發(fā)生數(shù)據(jù)copy,傳入函數(shù)的其實只是數(shù)組的一個副本,也就無法在函數(shù)內(nèi)部更改數(shù)組內(nèi)容。

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")
}

程序執(zhí)行結(jié)果為:

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

那么問題來了,如果想在函數(shù)內(nèi)部修改數(shù)組內(nèi)的數(shù)據(jù)怎么辦呢?這時候則使用數(shù)組切片。

數(shù)組切片

數(shù)組切片初看就像一個指向數(shù)組的指針,實際上它也有自己的數(shù)據(jù)結(jié)構(gòu),數(shù)組切片抽象為3個變量:

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

基于數(shù)組,數(shù)組切片添加了一系列管理功能,可以隨時動態(tài)擴展存儲空間,并且可以被隨意傳遞而不會導(dǎo)致管理的元素被重復(fù)復(fù)制。

創(chuàng)建數(shù)組切片

創(chuàng)建數(shù)組切片有兩種方式,基于數(shù)組(數(shù)組切片)和直接創(chuàng)建(使用內(nèi)置函數(shù)make())。我們通過例子來看兩種創(chuàng)建方式:

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

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

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

動態(tài)擴展元素

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

數(shù)組切片還有一個重要的功能就是可動態(tài)增減元素。數(shù)組切片支持內(nèi)置的cap()函數(shù),返回數(shù)組切片分配空間的大小??磦€例子:

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

內(nèi)容復(fù)制

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

copy(slice2, slice1)    //只復(fù)制slice1的前三個元素
copy(slice1, slice2)    //只復(fù)制slice2的3個元素到slice1的前三個位置

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

map

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

//定義一個struct
type bookInfo struct {
    ID string
    Name string
    Price string
}
func main() {
    var bookDB map[string] bookInfo
    bookDB = make(map[string] bookInfo)
    
    //插入數(shù)據(jù)
    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.

創(chuàng)建

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

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

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

刪除元素

使用內(nèi)置函數(shù)delete()來刪除map中的元素。例如:delete(bookDB, "123"),如果“123”不存在,則什么都不會發(fā)生,如果存在,則會刪除key為“123”的value。

查找元素

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

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

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容