溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Go語(yǔ)言之?dāng)?shù)組

發(fā)布時(shí)間:2020-05-25 19:38:21 來(lái)源:網(wǎng)絡(luò) 閱讀:328 作者:baby神 欄目:編程語(yǔ)言

數(shù)組,是用來(lái)存儲(chǔ)集合數(shù)據(jù)的。這種場(chǎng)景非常多,我們編碼的過(guò)程中,都少不了要讀取或者存儲(chǔ)數(shù)據(jù)。當(dāng)然除了數(shù)組之外,我們還有切片、Map映射等數(shù)據(jù)結(jié)構(gòu)可以幫我們存儲(chǔ)數(shù)據(jù),但是數(shù)組是它們的基礎(chǔ)。


內(nèi)部實(shí)現(xiàn)


要想更清晰地了解數(shù)組,我們先得了解它的內(nèi)部實(shí)現(xiàn)。數(shù)組是長(zhǎng)度固定的數(shù)據(jù)類(lèi)型,必須存儲(chǔ)一段相同類(lèi)型的元素,而且這些元素是連續(xù)的。我們這里強(qiáng)調(diào)固定長(zhǎng)度,可以說(shuō)這是和切片最明顯的區(qū)別。


數(shù)組存儲(chǔ)的類(lèi)型可以是內(nèi)置類(lèi)型,比如整型或者字符串;也可以是自定義的數(shù)據(jù)結(jié)構(gòu)。因?yàn)槭沁B續(xù)的,所以索引比較好計(jì)算,所以我們可以很快地索引數(shù)組中的任何數(shù)據(jù)。


這里的索引,一直都是0、1、2、3這樣的,因?yàn)槠湓仡?lèi)型相同。我們也可以使用反射,獲取類(lèi)型占用大小,進(jìn)行移位,獲取相應(yīng)的元素。這部分在說(shuō)到反射的時(shí)候,我們?cè)僦v。


聲明和初始化


數(shù)組的聲明和初始化,和其他類(lèi)型差不多。聲明的原則是:


  1. 指明存儲(chǔ)數(shù)據(jù)的類(lèi)型。

  2. 存儲(chǔ)元素的數(shù)量,也就是數(shù)組長(zhǎng)度。


var array [5]int


以上我們聲明了一個(gè)數(shù)組array,但是我們還沒(méi)有對(duì)他進(jìn)行初始化,這時(shí)候數(shù)組array里面的值,是對(duì)應(yīng)元素類(lèi)型的零值。也就是說(shuō),現(xiàn)在這個(gè)數(shù)組是 5 個(gè) 0 ,這和我們Java不一樣,Java里是null。


數(shù)組一旦聲明后,其元素類(lèi)型和大小都不能變了,如果還需要存儲(chǔ)更多的元素怎么辦?那么只能通過(guò)創(chuàng)建一個(gè)新的數(shù)組,然后把原來(lái)數(shù)組的數(shù)據(jù)復(fù)制過(guò)去。


剛剛聲明的數(shù)組已經(jīng)被默認(rèn)的元素類(lèi)型零值初始化了,如果我們?cè)俅芜M(jìn)行初始化怎么做呢,可以采用如下辦法:


var array [5]int
array = [5]int{1,2,3,4,5}


這兩步比較繁瑣,Go為我們提供了:=操作符,可以讓我們?cè)趧?chuàng)建數(shù)組的時(shí)候直接初始化。


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


這種簡(jiǎn)短變量聲明的方式不僅適用于數(shù)組,還適用于任何數(shù)據(jù)類(lèi)型,這也是Go語(yǔ)言中常用的方式。


有時(shí)候我們更懶,連數(shù)組的長(zhǎng)度都不想指定。不過(guò)沒(méi)有關(guān)系,使用…代替就好了,Go會(huì)自動(dòng)推導(dǎo)出數(shù)組的長(zhǎng)度。


array:=[...]int{1,2,3,4,5}


假如我們只想給索引為 1 和 3 的數(shù)組初始化相應(yīng)的值,其他都為 0 怎么做呢,直接的辦法有:


array:=[5]int{0,1,0,4,0}


還有一種更好的辦法,上面講默認(rèn)初始化為零值,那么我們就可以利用這個(gè)特性,只初始化索引 1 和 3 的值:


array:=[5]int{1:1,3:4}


使用數(shù)組


數(shù)組的訪(fǎng)問(wèn)非常簡(jiǎn)單,通過(guò)索引即可,操作符為[]。因?yàn)閮?nèi)存是連續(xù)的,所以索引訪(fǎng)問(wèn)的效率非常高。


array:=[5]int{1:1,3:4}
fmt.Printf("%d",array[1])


修改數(shù)組中的一個(gè)元素也很簡(jiǎn)單:


array:=[5]int{1:1,3:4}
fmt.Printf("%d\n",array[1])
array[1] = 3
fmt.Printf("%d\n",array[1])


如果我們要循環(huán)打印數(shù)組中的所有值,一個(gè)傳統(tǒng)的就是常用的for循環(huán):


func main() {
    array := [5]int{1: 1, 3: 4}

    for i := 0; i < 5; i++ {
        fmt.Printf("索引:%d,值:%d\n", i, array[i])
    }
}


不過(guò)大部分時(shí)候,我們都是使用for rang循環(huán):


func main() {
    array := [5]int{1: 1, 3: 4}

    for i, v := range array {
        fmt.Printf("索引:%d,值:%d\n", i, v)
    }
}


這兩段示例代碼,輸出的結(jié)果是一樣的。


同樣類(lèi)型的數(shù)組是可以相互賦值的,不同類(lèi)型的不行,會(huì)編譯錯(cuò)誤。那么什么是同樣類(lèi)型的數(shù)組呢?Go語(yǔ)言規(guī)定,必須是長(zhǎng)度一樣,并且每個(gè)元素的類(lèi)型也一樣的數(shù)組,才是同樣類(lèi)型的數(shù)組。


array := [5]int{1: 1, 3: 4}
var array1 [5]int = array //success
var array2 [4]int = array1 //error


指針數(shù)組和數(shù)組本身差不多,只不過(guò)元素類(lèi)型是指針。


array := [5]*int{1: new(int), 3:new(int)}


這樣就創(chuàng)建了一個(gè)指針數(shù)組,并且為索引 1 和 3 都創(chuàng)建了內(nèi)存空間,其他索引是指針的零值nil,這時(shí)候我們要修改指針變量的值也很簡(jiǎn)單,如下即可:


array := [5]*int{1: new(int), 3:new(int)}
*array[1] = 1


以上需要注意的是,只可以給索引 1 和 3 賦值,因?yàn)橹挥兴鼈兎峙淞藘?nèi)存,才可以賦值。如果我們給索引 0 賦值,運(yùn)行的時(shí)候,會(huì)提示無(wú)效內(nèi)存或者是一個(gè)nil指針引用。


panic: runtime error: invalid memory address or nil pointer dereference


要解決這個(gè)問(wèn)題,我們要先給索引 0 分配內(nèi)存,然后再進(jìn)行賦值修改。


array := [5]*int{1: new(int), 3:new(int)}
array[0] =new(int)
*array[0] = 2
fmt.Println(*array[0])


函數(shù)間傳遞數(shù)組


在函數(shù)間傳遞變量時(shí),總是以值的方式。如果變量是個(gè)數(shù)組,那么就會(huì)整個(gè)復(fù)制,并傳遞給函數(shù)。如果數(shù)組非常大,比如長(zhǎng)度 100 多萬(wàn),那么這對(duì)內(nèi)存是一個(gè)很大的開(kāi)銷(xiāo)。


func main() {
    array := [5]int{1: 2, 3:4}
    modify(array)
    fmt.Println(array)
}

func modify(a [5]int){
    a[1] =3
    fmt.Println(a)
}


通過(guò)上面的例子,可以看到,數(shù)組是復(fù)制的,原來(lái)的數(shù)組沒(méi)有修改。我們這里是 5 個(gè)長(zhǎng)度的數(shù)組還好,如果有幾百萬(wàn)怎么辦,有一種辦法是傳遞數(shù)組的指針,這樣,復(fù)制的大小只是一個(gè)數(shù)組類(lèi)型的指針大小。


func main() {
    array := [5]int{1: 2, 3:4}
    modify(&array)
    fmt.Println(array)
}

func modify(a *[5]int){
    a[1] =3
    fmt.Println(*a)
}


這是傳遞數(shù)組的指針的例子,會(huì)發(fā)現(xiàn)數(shù)組被修改了。所以這種情況雖然節(jié)省了復(fù)制的內(nèi)存,但是要謹(jǐn)慎使用,因?yàn)橐徊恍⌒?,就?huì)修改原數(shù)組,導(dǎo)致不必要的問(wèn)題。


這里注意,數(shù)組的指針和指針數(shù)組是兩個(gè)概念,數(shù)組的指針是*[5]int,指針數(shù)組是[5]*int,注意*的位置。


針對(duì)函數(shù)間傳遞數(shù)組的問(wèn)題,比如復(fù)制問(wèn)題,比如大小僵化問(wèn)題,都有更好的解決辦法,這個(gè)就是切片,它更靈活


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI