日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Golang 入门 : 数组

發(fā)布時間:2024/8/26 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Golang 入门 : 数组 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

數(shù)組是指一系列同一類型數(shù)據(jù)的集合。數(shù)組中包含的每個數(shù)據(jù)被稱為數(shù)組元素(element),這種類型可以是任意的原始類型,比如 int、string 等,也可以是用戶自定義的類型。一個數(shù)組包含的元素個數(shù)被稱為數(shù)組的長度。在 Golang 中數(shù)組是一個長度固定的數(shù)據(jù)類型,數(shù)組的長度是類型的一部分,也就是說 [5]int 和 [10]int 是兩個不同的類型。Golang 中數(shù)組的另一個特點(diǎn)是占用內(nèi)存的連續(xù)性,也就是說數(shù)組中的元素是被分配到連續(xù)的內(nèi)存地址中的,因而索引數(shù)組元素的速度非常快。

本文將介紹 Golang 數(shù)組的基本概念和用法,演示環(huán)境為 ubuntu 18.04 & go1.10.1。

Golang 數(shù)組的特點(diǎn)

我們可以把 Golang 數(shù)組的特征歸納為以下三點(diǎn):

  • 固定長度:這意味著數(shù)組不可增長、不可縮減。想要擴(kuò)展數(shù)組,只能創(chuàng)建新數(shù)組,將原數(shù)組的元素復(fù)制到新數(shù)組。
  • 內(nèi)存連續(xù):這意味可以在緩存中保留的時間更長,搜索速度更快,是一種非常高效的數(shù)據(jù)結(jié)構(gòu),同時還意味著可以通過數(shù)值的方式(arr[index])索引數(shù)組中的元素。
  • 固定類型:固定類型意味著限制了每個數(shù)組元素可以存放什么樣的數(shù)據(jù),以及每個元素可以存放多少字節(jié)的數(shù)據(jù)。

數(shù)組是個固定長度的數(shù)據(jù)類型,其長度和存儲元素的數(shù)據(jù)類型都在聲明數(shù)組時確定,并且不能更改。如果需要存儲更多的元素,必須先創(chuàng)建一個更長的數(shù)組,然后把原來數(shù)組里的數(shù)據(jù)復(fù)制到新數(shù)組中。
數(shù)組占用的內(nèi)存是連續(xù)分配的,比如我們創(chuàng)建一個包含 5 個整數(shù)元素的數(shù)組:

arr1 := [5]int{10,20,30,40,50}

數(shù)組在內(nèi)存中的結(jié)構(gòu)類似下圖:

由于內(nèi)存連續(xù),CPU 能把正在使用的數(shù)據(jù)緩存更久的時間。而且在內(nèi)存連續(xù)的情況下非常容易計算索引,也就是說可以快速迭代數(shù)組里的所有元素。原因是數(shù)組的類型信息可以提供每次訪問一個元素時需要在內(nèi)存中移動的距離,既然數(shù)組的每個元素的類型都相同,又是連續(xù)分配,因此就可以以固定的速度索引數(shù)組中的任意元素,并且速度非常快!

數(shù)組的聲明與初始化

聲明數(shù)組
聲明數(shù)組時需要指定數(shù)組的長度和數(shù)組中元素的類型,比如聲明一個包含 5 個元素,類型為 int 的數(shù)組:

var arr1 [5]int

這里強(qiáng)調(diào)一點(diǎn),數(shù)組的類型是包含數(shù)組長度的,因此 [5]int 和 [10]int 是兩個不同類型的數(shù)組。
在 Go 語言中聲明變量時,總會使用對應(yīng)類型的零值來初始化變量,數(shù)組也不例外。當(dāng)聲明數(shù)組變量時,數(shù)組內(nèi)的每個元素被初始化為對應(yīng)類型的零值。比如變量 arr1,它的 5 個元素都被初始化成了 int 類型的零值 0。使用 fmt.Println(arr1) 可以看到數(shù)組中元素的值:

package main import "fmt" func main(){var arr1 [5]intfmt.Println(arr1) // 輸出為:[0 0 0 0 0] }

你可以把此時數(shù)組在內(nèi)存中的狀態(tài)想象為下圖所示的樣子:

使用字面量初始化數(shù)組
我們可以通過字面量在聲明數(shù)組的同時快速的初始化數(shù)組:

arr2 := [5]int{10,20,30,40,50}

對于這種情況,還可以使用 … 代替數(shù)組的長度,讓編譯器根據(jù)實(shí)際的元素個數(shù)自行推斷數(shù)組的長度:

arr3 := […]int{10,20,30,40,50}

如果設(shè)置了數(shù)組的長度,還可以通過指定下標(biāo)的方式初始化部分元素:

// 用具體值初始化索引為 1 和 3 的元素 arr4 := [5]int{1:20,3:40}

數(shù)組的內(nèi)容如下圖所示:

訪問與修改數(shù)組元素

和其它類 C 語言一樣,Go 語言數(shù)組通過數(shù)組下標(biāo)(索引位置)來讀取或者修改數(shù)組元素。下標(biāo)(索引)從 0 開始,第一個元素的索引為 0,第二個索引為 1,依次類推。元素的數(shù)目(數(shù)組長度)必須是固定的并且在聲明數(shù)組時就指定(編譯器需要知道數(shù)組的長度以便分配內(nèi)存),數(shù)組長度最大為 2G。

訪問數(shù)組元素
對于數(shù)組 arr 來說,第一個元素就是 arr[0],第二個元素是 arr[1],最后一個元素則是 arr[len(arr)-1]。下面的代碼定義一個整型數(shù)組,然后通過 for 循環(huán)打印數(shù)組中的每個元素:

package main import "fmt" func main(){arr := [5]int{10,20,30,40,50}for i := 0; i < len(arr); i++ {fmt.Printf("At index %d is %d\n", i, arr[i])} }

運(yùn)行上面的代碼,輸出如下:

At index 0 is 10 At index 1 is 20 At index 2 is 30 At index 3 is 40 At index 4 is 50

除了使用 len() 函數(shù)通過索引遍歷數(shù)組,還可以使用更方便的 range,結(jié)果都是一樣的:

for index,value := range arr {fmt.Printf("At index %d is %d\n", index, value) }

修改數(shù)組元素
要修改單個元素的值,直接通過下標(biāo)訪問元素并賦值就可以了:

arr := [5]int{10,20,30,40,50} arr[2] = 35

指針數(shù)組
數(shù)組的元素除了是某個類型外,還可以是某個類型的指針,下面聲明一個所有元素都是指針的數(shù)組,然后使用 * 運(yùn)算符就可以訪問元素指針?biāo)赶虻闹?#xff1a;

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

new(TYPE) 函數(shù)會為一個 TYPE 類型的數(shù)據(jù)結(jié)構(gòu)劃分內(nèi)存并執(zhí)行默認(rèn)的初始化操作,然后返回這個數(shù)據(jù)對象的指針,所以 new(int) 表示創(chuàng)建一個 int 類型的數(shù)據(jù)對象,同時返回指向這個對象的指針。

// 為索引為 0 和 1 的元素賦值 *arr[0] = 10 *arr[1] = 20

完成賦值后的結(jié)果如下:

我們還可以接著初始化剩下的元素并賦值:

arr[2] = new(int) arr[3] = new(int) arr[4] = new(int) *arr[2] = 30

最后打印整個指針數(shù)組指向的內(nèi)容:

for i := 0; i < len(arr); i++ {fmt.Printf("At index %d is %d\n", i, *arr[i]) }

結(jié)果如下:

At index 0 is 10 At index 1 is 20 At index 2 is 30 At index 3 is 0 At index 4 is 0

數(shù)組是值類型

在 Golang 中,數(shù)組是值類型,這意味著數(shù)組也可以用在賦值操作中。變量名代表整個數(shù)組,同類型的數(shù)組可以賦值給另一個數(shù)組:

var arr1 [3]string arr2 := [3]string{"nick", "jack", "mark"} // 把 arr2 的賦值(其實(shí)本質(zhì)上是復(fù)制)到 arr1 arr1 = arr2

復(fù)制完成后兩個數(shù)組的值完全一樣,但是彼此之間沒有任何關(guān)系:

前面我們不止一次地提到:數(shù)組的類型包括數(shù)組的長度和數(shù)組元素的類型。只有這兩部分都一樣才是相同類型的數(shù)組,也才能夠互相賦值。下面的代碼中,在類型不同的數(shù)組間賦值,編譯器會阻止這樣的操作并報錯:

// 聲明第一個包含 4 個元素的字符串?dāng)?shù)組 var arr1 [4]string // 聲明第二個包含 3 個元素的字符串?dāng)?shù)組,并初始化 arr2 := [3]string{"nick", "jack", "mark"} // 將 arr2 賦值給 arr1 arr1 = arr2

編譯器表示在賦值時不能把 type [3]string 當(dāng) type [4]string 用。

把數(shù)組賦值給其它數(shù)組時,實(shí)際上是完整地復(fù)制一個數(shù)組。所以,如果數(shù)組是一個指針型的數(shù)組,那么復(fù)制的將是指針,而不會復(fù)制指針?biāo)赶虻膶ο蟆?聪旅娴拇a:

// 聲明第一個包含 4 個元素的字符串?dāng)?shù)組 var arr1 [3]*string // 聲明第二個包含 3 個元素的字符串?dāng)?shù)組,并初始化 arr2 := [3]*string{new(string), new(string), new(string)} *arr2[0] = "nick" *arr2[1] = "jack" *arr2[2] = "mark" // 將 arr2 賦值給 arr1 arr1 = arr2

在賦值完成后,兩個數(shù)組指向的是同一組字符串:

把數(shù)組傳遞給函數(shù)

在 Golang 中數(shù)組是一個值類型,所有的值類型變量在賦值和作為參數(shù)傳遞時都將產(chǎn)生一次復(fù)制操作。如果直接將數(shù)組作為函數(shù)的參數(shù),則在函數(shù)調(diào)用時數(shù)組會被復(fù)制一份傳遞給函數(shù)。因此,在函數(shù)體中無法修改源數(shù)組的內(nèi)容,因?yàn)楹瘮?shù)內(nèi)操作的只是源數(shù)組的一個副本。
如此一來,從內(nèi)存和性能上來看,在函數(shù)間傳遞數(shù)組是一個開銷很大的操作。因?yàn)闊o論這個數(shù)組有多長,都會完整復(fù)制,并傳遞給函數(shù)。下面的 demo 中會聲明一個包含 100 萬個 int64 類型元素的數(shù)組,這會消耗掉 8MB 的內(nèi)存:

func showArray(array [1e6]int64){// do something } var arr [1e6]int64 showArray(arr)

每次函數(shù) showArray 被調(diào)用時,必須在棧上分配 8MB 的內(nèi)存。之后整個數(shù)組的值(8MB 內(nèi)存) 被復(fù)制到剛剛分配的內(nèi)存中。雖然 Golang 的運(yùn)行時會自動處理這個復(fù)制操作,但這樣做的效率實(shí)在是太低了,也太耗費(fèi)內(nèi)存!合理且高效的方式是只傳入指向數(shù)組的指針,這樣只需復(fù)制 8 個字節(jié)的數(shù)據(jù)到函數(shù)的棧上就可以了:

func showArray(array *[1e6]int64){// do something } var arr [1e6]int64 showArray(&arr)

這段代碼中的 showArray 函數(shù)接收一個指向包含 100 萬個 int64 值的數(shù)組的指針,調(diào)用函數(shù)時傳入的參數(shù)則是指向數(shù)組的指針。現(xiàn)在只需在棧上分配 8 個字節(jié)的內(nèi)存給這個指針就行了。
這個方法能夠更有效地利用內(nèi)存,性能也更好。需要注意的是,此時在函數(shù)內(nèi)外操作的都是同一個數(shù)組中的元素,會互相影響。

多維數(shù)組

多維數(shù)組的典型用例是平面坐標(biāo)(二維數(shù)組)和三維坐標(biāo)(三維數(shù)組),這里我們簡單介紹一下二維數(shù)組。
Golang 的數(shù)組本身只有一個維度,但是我們可以組合多個數(shù)組從而創(chuàng)建出多維數(shù)組,下面是聲明二維數(shù)組的實(shí)例代碼:

// 聲明一個二維整型數(shù)組,兩個維度分別存儲 4 個元素和 2 個元素 var arr [4][2]int // 使用數(shù)組字面量來聲明并初始化一個二維整型數(shù)組 arr1 := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}} // 聲明并初始化外層數(shù)組中索引為 1 和 3 的元素 arr2 := [4][2]int{1: {20, 21}, 3: {40, 41}} // 聲明并初始化外層數(shù)組和內(nèi)層數(shù)組的單個元素 arr3 := [4][2]int{1: {0: 20}, 3: {1: 41}}

下圖展示了上面代碼聲明的二維數(shù)組在每次聲明并初始化后包含的值:

為了訪問單個元素,需要反復(fù)組合使用 [] 運(yùn)算符,比如:

arr1[0][0] = 666

因?yàn)槊總€數(shù)組都是一個值,所以可以獨(dú)立復(fù)制某個維度:

// 將 arr1 的索引為 1 的維度復(fù)制到一個同類型的新數(shù)組里 var arr4 [2]int = arr1[1] // 將外層數(shù)組的索引為 1、內(nèi)層數(shù)組的索引為 0 的整型值復(fù)制到新的整型變量里 var value int = arr1[1][0]

總結(jié)

數(shù)組在 Golang 中是作為高性能的基礎(chǔ)類型設(shè)計的,因此對用戶來說使用起來并不是特別方便,這一點(diǎn)在眾多的開源代碼中(數(shù)組用的少,slice 用的多)可以得到印證。其實(shí)基于數(shù)組實(shí)現(xiàn)的 slice 以其簡單靈活的特性更易于被大家接受,這也正是 Golang 設(shè)計 slice 的初衷。本文介紹了數(shù)組這個幕后大英雄,后面的文章會介紹 slice 的用法。

參考:
Golang Array? types
《Go語言編程》
《Go語言實(shí)戰(zhàn)》
go基礎(chǔ)系列:數(shù)組

轉(zhuǎn)載于:https://www.cnblogs.com/sparkdev/p/10704389.html

總結(jié)

以上是生活随笔為你收集整理的Golang 入门 : 数组的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。