Go語言數組


數組是具有相同唯一類型的一組已編號且長度固定的數據項序列(這是一種同構的數據結構);這種類型可以是任意的原始類型例如整形、字符串或者自定義類型(結構體、接口)。數組長度必須是一個常量表達式,並且必須是一個非負整數,數組下標是從0開始的,並且數組的長度是固定不可變的,數組中元素的地址是連續的。數組長度也是數組類型的一部分,所以[5]int和[10]int是屬於不同類型的。

在其它編程語言中,數組一般都是引用類型,而在Go語言中,數組屬於值類型。

注意:如果我們想讓數組元素類型為任意類型的話可以使用空接口作為類型。當使用值時我們必須先做一個類型判斷。

聲明數組

Go語言數組聲明需要指定元素類型及元素個數,語法格式如下:

//  變量名          [大小]類型
var variable_name [len]variable_type

示例:

定義一個長度為5的數組arr

var arr [5]int

以上我們聲明了一個數組arr,但是我們還沒有對他進行初始化,但是聲明的變量都會有默認值,int類型的變量默認值是0,所以arr數組中的每個元素的值都是0。
Go語言中的數組是一種值類型,所以可以通過 new() 來創建: var arr1 = new([5]int) 。那么這種方式和 var arr2 [5]int 的區別是什么呢?arr1 的類型是 *[5]int ,而 arr2的類型是 [5]int

數組在內存的結構

假如我們聲明一個長度為5的數組var arr [5]int,我們來看看這個數組在內存中的結構是怎么樣的。

上圖就是一個Go語言數組在內存的結構,在這個arr數組中,由於我們聲明的是int32類型,所以數組中的每個元素在內存中占用的字節數是32/8=4字節,通過arr數組每個元素16進制地址我們可以發現,數組中后一個元素的地址比前一個元素的地址大4個字節,這個4字節正好是int32類型元素占用的內存大小,由此我們也能得出結論:數組中元素的內存地址是連續的;當聲明數組時所有的元素都會被自動初始化為數組類型的默認值(int類型的默認值是0,所以arr中每個元素的默認值都是0);數組的下標識從0開始的。數組arr的地址就是數組第一個元素(下標為0的元素)的地址,通過下圖打印arr的地址和arr[0]的地址就可以證明

初始化數組

剛剛聲明的數組已經被默認的元素類型零值初始化了,如果我們再次進行初始化怎么做呢,可以采用如下辦法:

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

Go語言提供了聲明加初始化的:=操作符,以讓我們在創建數組的時候直接初始化。

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

這種簡短變量聲明的方式不僅適用於數組,還適用於任何數據類型,這也是Go語言中常用的方式。

我們也可以在定義數組是不明確指定長度,讓編譯器自動推導出長度,可以使用...來替代具體的長度

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

如果我們只想給數組的部分元素指定值,其他元素采用默認值我們可以采用下面的辦法

arr := [5]int{0:3, 4:6}

這種方式表示我們只給數組下標為0的元素賦值為3,下標為4的元素賦值為6,其它元素的值依然是該類型的默認值(int的默認值是0)。

使用數組

數組元素的訪問非常簡單,通過索引(下標)即可訪問數組的元素。

arr := [5]int{1, 2, 3, 4, 5}
fmt.Println(arr[0], arr[1], arr[2], arr[3], arr[4])

修改數組的某個元素也很簡單:

arr := [5]int{1, 2, 3, 4, 5}
fmt.Println(arr[0])
arr[0] = 66
fmt.Println(arr[0])

如果我們要循環打印數組中的所有值,一個傳統的就是常用的for循環:

for i := 0; i < len(arr); i++ {
    fmt.Println(arr[i])
}

不過大部分時候,我們都是使用for rang循環:

for i, v := range arr {
    fmt.Println("索引是:", i, "值是:", v)
}

同樣類型的數組是可以相互賦值的,不同類型的不行,會編譯錯誤。那么什么是同樣類型的數組呢?Go語言規定,必須是長度一樣,並且每個元素的類型也一樣的數組,才是同樣類型的數組。

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

var arr2 [5]int = arr //可以
var arr3 [3]int = arr //不可以

指針數組和數組本身差不多,只不過元素類型是指針。

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

這樣就創建了一個指針數組,並且為索引1和3都創建了內存空間,其他索引是指針的零值nil,這時候我們要修改指針變量的值也很簡單,如下即可:

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

以上需要注意的是,只可以給索引1和3賦值,因為只有它們分配了內存,才可以賦值,如果我們給索引0賦值,運行的時候,會提示無效內存或者是一個nil指針引用。

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

要解決這個問題,我們要先給索引0分配內存,然后再進行賦值修改。

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

函數間傳遞數組

在Go中,數組也是值類型,所以在函數間傳遞變量時,么就會整個復制,並傳遞給函數,如果數組非常大,比如長度100多萬,那么這對內存是一個很大的開銷。

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

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

通過上面的例子,可以看到,數組是復制的,原來的數組沒有修改。我們這里是5個長度的數組還好,如果有幾百萬怎么辦,有一種辦法是傳遞數組的指針,這樣,復制的大小只是一個數組類型的指針大小。

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

func modify(a *[5]int){
	a[1] = 333
}

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

數組使用注意事項

  1. 數組是多個相同類型數據的組合,一個數組一旦聲明/定義了,其長度是固定的,不能動態變化。

  2. 數組中的元素可以是任何數據類型,包括值類型和引用類型,但是不能混用。

  3. 數組創建后,如果沒有賦值,有默認值

    數值類型數組:默認值為0

    字符串類型數組:默認值為""

    bool數組: 默認值為false
    指針數組: 默認值nil

  4. 使用數組的步驟:1.聲明數組並開辟空間2.給數組各個元素賦值3.使用數組

  5. 數組的下標從0開始

  6. 數組下標必須在指定范圍內使用,否則報panic:數組越界

  7. Go的數組屬於值類型 ,在默認情況下是值傳遞,因此會進行值拷貝。數組間不會相互影響

  8. 如果想在其它函數中,去修改原來的數組,可以使用引用傳遞(指針方式)

  9. 長度是數組類型的一部分,在傳遞函數參數時,需要考慮數組的長度


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM