日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

GO中?分組聲明與array,?slice,?map函數(shù)_Golang

作者:蘇州程序大白 ? 更新時(shí)間: 2022-06-02 編程語(yǔ)言

前言:

在 Go 語(yǔ)言中,同時(shí)聲明多個(gè)常量、變量,或者導(dǎo)入多個(gè)包時(shí),可采用分組的方式進(jìn)行聲明。

例如下面的代碼:

import "fmt"
import "os"

const i = 100
const pi = 3.1415
const prefix = "Go_"

var i int
var pi float32
var prefix string1

可以改成下面的方式:

import(
? ? "fmt"
? ? "os"
)

const(
? ? i = 100
? ? pi = 3.1415
? ? prefix = "Go_"
)

var(
? ? i int
? ? pi float32
? ? prefix string
)

iota 枚舉

Go 里面有一個(gè)關(guān)鍵字 iota,這個(gè)關(guān)鍵字用來(lái)聲明 enum 的時(shí)候采用,它默認(rèn)開(kāi)始值是 0,每調(diào)用一次加 1:

const(
? ? x = iota // x == 0
? ? y = iota // y == 1
? ? z = iota // z == 2
? ? w // 常量聲明省略值時(shí),默認(rèn)和之前一個(gè)值的字面相同。
? ? ? //這里隱式地說(shuō) w =
? ? ? //iota,因此 w == 3。其實(shí)上面 y 和 z 可同樣不用"= iota"
)

注:const v = iota // 每遇到一個(gè) const 關(guān)鍵字,iota 就會(huì)重置,此時(shí) v == 0。

Go 程序設(shè)計(jì)的一些規(guī)則

Go 之所以會(huì)那么簡(jiǎn)潔,是因?yàn)樗幸恍┠J(rèn)的行為:

  • 大寫(xiě)字母開(kāi)頭的變量是可導(dǎo)出的,也就是其它包可以讀取的,是公用變量;小寫(xiě)字母開(kāi)頭的就是不可導(dǎo)出的,是私有變量
  • 大寫(xiě)字母開(kāi)頭的函數(shù)也是一樣,相當(dāng)于 class 中的帶 public 關(guān)鍵詞的公有函數(shù);小寫(xiě)字母開(kāi)頭的就是有 private 關(guān)鍵詞的私有函數(shù)。

數(shù)組

array 就是數(shù)組,它的定義方式如下:

var arr [n]type

在[n]type 中,n 表示數(shù)組的長(zhǎng)度,type 表示存儲(chǔ)元素的類(lèi)型。對(duì)數(shù)組的操作和其它語(yǔ)言類(lèi)似,都是通過(guò)[]來(lái)進(jìn)行讀取或賦值:

var arr [10]int // 聲明了一個(gè) int 類(lèi)型的數(shù)組
arr[0] = 42 // 數(shù)組下標(biāo)是從 0 開(kāi)始的
arr[1] = 13 // 賦值操作
fmt.Printf("The first element is %d\n", arr[0]) // 獲取數(shù)據(jù),返回 42
fmt.Printf("The last element is %d\n", arr[9]) //返回未賦值的最后一個(gè)元素,默認(rèn)返回 0

由于長(zhǎng)度也是數(shù)組類(lèi)型的一部分,因此[3]int 與[4]int 是不同的類(lèi)型,數(shù)組也就不能改變長(zhǎng)度。

數(shù)組之間的賦值是值的賦值,即當(dāng)把一個(gè)數(shù)組作為參數(shù)傳入函數(shù)的時(shí)候,傳入的其實(shí)是該數(shù)組的副本,而不是它的指針。

如果要使用指針,那么就需要用到后面介紹的 slice 類(lèi)型了。

數(shù)組可以使用另一種:=來(lái)聲明。

a := [3]int{1, 2, 3} // 聲明了一個(gè)長(zhǎng)度為 3 的 int 數(shù)組
b := [10]int{1, 2, 3} // 聲明了一個(gè)長(zhǎng)度為 10 的 int 數(shù)組,其中前三個(gè)元素初始化為 1、2、3,其它默認(rèn)
為 0
c := [...]int{4, 5, 6} // 可以省略長(zhǎng)度而采用`...`的方式,Go 會(huì)自動(dòng)根據(jù)元素個(gè)數(shù)來(lái)計(jì)算長(zhǎng)度

也許你會(huì)說(shuō),我想數(shù)組里面的值還是數(shù)組,能實(shí)現(xiàn)嗎?

當(dāng)然咯,Go 支持嵌套數(shù)組,即多維 數(shù)組。

比如下面的代碼就聲明了一個(gè)二維數(shù)組:

// 聲明了一個(gè)二維數(shù)組,該數(shù)組以?xún)蓚€(gè)數(shù)組作為元素,其中每個(gè)數(shù)組中又有 4 個(gè) int 類(lèi)型的元素
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}

// 如果內(nèi)部的元素和外部的一樣,那么上面的聲明可以簡(jiǎn)化,直接忽略?xún)?nèi)部的
類(lèi)型
easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}

數(shù)組的分配如下所示:

切片

在很多應(yīng)用場(chǎng)景中,數(shù)組并不能滿足我們的需求。在初始定義數(shù)組時(shí),我們并不知道需要多大的數(shù)組,因此我們就需要“動(dòng)態(tài)數(shù)組”。在 Go 里面這種數(shù)據(jù)結(jié)構(gòu)叫 slice , 翻譯過(guò)來(lái)就是切片的意思,大白話就是切成一片一片的:

  • slice 并不是真正意義上的動(dòng)態(tài)數(shù)組,而是一個(gè)引用類(lèi)型。
  • slice 總是指向一個(gè)底層array。
  • slice 的聲明也可以像 array 一樣,只是不需要長(zhǎng)度。
// 和聲明 array 一樣,只是少了長(zhǎng)度
var fslice []int

接下來(lái)我們可以聲明一個(gè) slice,并初始化數(shù)據(jù),如下所示:

slice := []byte {'a', 'b', 'c', 'd'}
  • slice 可以從一個(gè)數(shù)組或一個(gè)已經(jīng)存在的 slice 中再次聲明。
  • slice 通過(guò) array[i:j]來(lái)獲取,其中 i 是數(shù)組的開(kāi)始位置,j 是結(jié)束位置,但不包含 array[j],即[i,j),前包括后不包括, 它的長(zhǎng)度是 j-i。
// 聲明一個(gè)含有 10 個(gè)元素元素類(lèi)型為 byte 的數(shù)組
var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// 聲明兩個(gè)含有 byte 的 slice
var a, b []byte
// a 指向數(shù)組的第 3 個(gè)元素開(kāi)始,并到第五個(gè)元素結(jié)束,
a = ar[2:5]
//現(xiàn)在 a 含有的元素: ar[2]、ar[3]和 ar[4]

// b 是數(shù)組 ar 的另一個(gè) slice
b = ar[3:5]
// b 的元素是:ar[3]和 ar[4]

注意 slice 和數(shù)組在聲明時(shí)的區(qū)別:

  • 聲明數(shù)組時(shí),方括號(hào)內(nèi)寫(xiě)明了數(shù)組的長(zhǎng)度或使用...。
  • 自動(dòng)計(jì)算長(zhǎng)度,而聲明 slice 時(shí),方括號(hào)內(nèi)沒(méi)有任何字符。

它們的數(shù)據(jù)結(jié)構(gòu)如下所示:

slice 有一些簡(jiǎn)便的操作:

  • slice 的默認(rèn)開(kāi)始位置是 0,ar[:n]等價(jià)于 ar[0:n]。
  • slice 的第二個(gè)序列默認(rèn)是數(shù)組的長(zhǎng)度,ar[n:]等價(jià)于ar[n:len(ar)]。
  • 如果從一個(gè)數(shù)組里面直接獲取 slice,可以這樣 ar[:],因?yàn)槟J(rèn)第一個(gè)序列是 0,第 二個(gè)是數(shù)組的長(zhǎng)度,即等價(jià)于 ar[0:len(ar)]。

下面這個(gè)例子展示了更多關(guān)于 slice 的操作:

// 聲明一個(gè)數(shù)組
var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}

// 聲明兩個(gè) slice
var aSlice, bSlice []byte

// 演示一些簡(jiǎn)便操作
aSlice = array[:3] // 等價(jià)于 aSlice = array[0:3] aSlice 包含元素: a,b,c
aSlice = array[5:] // 等價(jià)于 aSlice = array[5:10] aSlice 包含元素: f,g,h,i,j

aSlice = array[:] // 等價(jià)于 aSlice = array[0:10] 這樣 aSlice 包含了全部的元素

// 從 slice 中獲取 slice
aSlice = array[3:7] // aSlice 包含元素: d,e,f,g,len=4,cap=7

bSlice = aSlice[1:3] // bSlice 包含 aSlice[1], aSlice[2] 也就是含有: e,f

bSlice = aSlice[:3] // bSlice 包含 aSlice[0], aSlice[1], aSlice[2] 也就是
含有: d,e,f

bSlice = aSlice[0:5] // 對(duì) slice 的 slice 可以在 cap 范圍內(nèi)擴(kuò)展,此時(shí)
bSlice 包含:d,e,f,g,h

bSlice = aSlice[:] // bSlice 包含所有 aSlice 的元素: d,e,f,g

slice 是引用類(lèi)型,所以當(dāng)引用改變其中元素的值時(shí),其它的所有引用都會(huì)改變?cè)撝担缟厦娴腶Slice 和bSlice,如果修改了aSlice中元素的值,那么 bSlice相對(duì)應(yīng)的值也會(huì)改變。 從概念上面來(lái)說(shuō) slice像一個(gè)結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體包含了三個(gè)元素:

  • 一個(gè)指針,指向數(shù)組中slice指定的開(kāi)始位置。
  • 長(zhǎng)度,即 slice 的長(zhǎng)度。
  • 最大長(zhǎng)度,也就是 slice 開(kāi)始位置到數(shù)組的最后位置的長(zhǎng)度。
Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}

Slice_a := Array_a[2:5]

上面代碼的真正存儲(chǔ)結(jié)構(gòu)如下圖所示:

對(duì)于 slice 有幾個(gè)有用的內(nèi)置函數(shù):

  • len 獲取 slice 的長(zhǎng)度。
  • cap 獲取 slice 的最大容量。
  • append 向 slice 里面追加一個(gè)或者多個(gè)元素,然后返回一個(gè)和 slice 一樣類(lèi)型的slice。
  • copy 函數(shù) copy 從源 slice 的 src 中復(fù)制元素到目標(biāo) dst,并且返回復(fù)制的元素的個(gè)數(shù)。

注:append 函數(shù)會(huì)改變 slice 所引用的數(shù)組的內(nèi)容,從而影響到引用同一數(shù)組的其它 slice。

但當(dāng) slice 中沒(méi)有剩余空間(即(cap-len) == 0)時(shí),此時(shí)將動(dòng)態(tài)分配新的數(shù)組空間。

返回的slice 數(shù)組指針將指向這個(gè)空間,而原數(shù)組的內(nèi)容將保持不變;

其它引用此數(shù)組的 slice 則不受影響。

map

map 也就是 Python 中字典的概念,它的格式為 map[keyType]valueType我們看下面的代碼,map 的讀取和設(shè)置也類(lèi)似 slice 一樣,通過(guò) key 來(lái)操作,只是 slice 的index只能是int類(lèi)型,而 map 多了很多類(lèi)型,可以是 int,可以是 string 及所有完全定
義了==與!=操作的類(lèi)型。

// 聲明一個(gè) key 是字符串,值為 int 的字典,這種方式的聲明需要在使用之前使用 make 初始化
var numbers map[string] int
// 另一種 map 的聲明方式
numbers := make(map[string]int)
numbers["one"] = 1 //賦值
numbers["ten"] = 10 //賦值
numbers["three"] = 3
fmt.Println("第三個(gè)數(shù)字是: ", numbers["three"]) // 讀取數(shù)據(jù)
// 打印出來(lái)如:第三個(gè)數(shù)字是: 3

這個(gè) map 就像我們平常看到的表格一樣,左邊列是 key,右邊列是值使用 map 過(guò)程中需要注意的幾點(diǎn):

  • map 是無(wú)序的,每次打印出來(lái)的 map 都會(huì)不一樣,它不能通過(guò) index 獲取,而必須通過(guò) key 獲取。
  • map 的長(zhǎng)度是不固定的,也就是和 slice 一樣,也是一種引用類(lèi)型。
  • 內(nèi)置的 len 函數(shù)同樣適用于 map,返回 map 擁有的 key 的數(shù)量。
  • map 的值可以很方便的修改,通過(guò) numbers["one"]=11 可以很容易的把 key 為 one 的字典值改為 11。

map 的初始化可以通過(guò) key:val 的方式初始化值,同時(shí) map 內(nèi)置有判斷是否存在 key 的方式,通過(guò) delete 刪除 map 的元素:

// 初始化一個(gè)字典
rating := map[string]float32 {"C":5, "Go":4.5, "Python":4.5, "C++":2 }
// map 有兩個(gè)返回值,第二個(gè)返回值,如果不存在 key,那么 ok 為 false,如果存在 ok 為 true
csharpRating, ok := rating["C#"]
if ok {
? ? fmt.Println("C# is in the map and its rating is ", csharpRating)
} else {
? ? fmt.Println("We have no rating associated with C# in the map")
}
delete(rating, "C") // 刪除 key 為 C 的元素

上面說(shuō)過(guò)了,map 也是一種引用類(lèi)型,如果兩個(gè) map 同時(shí)指向一個(gè)底層,那么一個(gè)改變, 另一個(gè)也相應(yīng)的改變:

m := make(map[string]string)
m["Hello"] = "Bonjour"
m1 := m
m1["Hello"] = "Salut" // 現(xiàn)在 m["hello"]的值已經(jīng)是 Salut 了

make、new 操作

  • make用于內(nèi)建類(lèi)型(map、slice 和 channel)的內(nèi)存分配。
  • new 用于各種類(lèi)型的內(nèi)存分配。
  • 內(nèi)建函數(shù) new 本質(zhì)上說(shuō)跟其它語(yǔ)言中的同名函數(shù)功能一樣:new(T)分配了零值填充的 T 類(lèi)型的內(nèi)存空間,并且返回其地址,即一個(gè)*T類(lèi)型的值。用 Go 的術(shù)語(yǔ)說(shuō),它返回了一個(gè)指針,指向新分配的類(lèi)型 T的零值。
  • 有一點(diǎn)非常重要:new 返回指針。
  • 內(nèi)建函數(shù)make(T, args)與 new(T)有著不同的功能,make 只能創(chuàng)建 slice、map 和 channel,并且返回一個(gè)有初始值(非零)的 T 類(lèi)型,而不是*T。
  • 本質(zhì)來(lái)講,導(dǎo)致這三個(gè)類(lèi)型有所不同的 原因是指向數(shù)據(jù)結(jié)構(gòu)的引用在使用前必須被初始化。例如,一個(gè) slice,是一個(gè)包含指向數(shù) 據(jù)(內(nèi)部 array)的指針、長(zhǎng)度和容量的三項(xiàng)描述符;在這些項(xiàng)目被初始化之前,slice為nil。
  • 對(duì)于 slice、map 和 channel 來(lái)說(shuō),make初始化了內(nèi)部的數(shù)據(jù)結(jié)構(gòu),填充適當(dāng)?shù)闹怠?/li>
  • make 返回初始化后的(非零)值。下面這個(gè)圖詳細(xì)的解釋了 new 和 make 之間的區(qū)別。

關(guān)于“零值”,所指并非是空值,而是一種“變量未填充前”的默認(rèn)值,通常為0。 此處羅列部分類(lèi)型 的“零值”。

int ? ? 0
int8 ? ? 0
int32 ? ? 0
int64 ? ? 0
uint ? ? 0x0
rune ? ? 0 //rune 的實(shí)際類(lèi)型是 int32
byte ? ? 0x0 // byte 的實(shí)際類(lèi)型是 uint8
float32 0 //長(zhǎng)度為 4 byte
float64 0 //長(zhǎng)度為 8 byte
bool ? ? false
string ? ? ""

原文鏈接:https://blog.csdn.net/weixin_46931877/article/details/122424219

欄目分類(lèi)
最近更新