網(wǎng)站首頁(yè) 編程語(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
相關(guān)推薦
- 2022-08-28 本周遇到的一些問(wèn)題整理,有些未完全解決,留在下周寫(xiě)
- 2022-12-01 Python?Flask前端自動(dòng)登錄功能實(shí)現(xiàn)詳解_python
- 2022-11-22 Python?arrow模塊使用方法_python
- 2023-09-12 Spring Boot注解說(shuō)明
- 2023-04-19 微信小程序授權(quán)登錄三種實(shí)現(xiàn)方式
- 2022-08-10 Github簡(jiǎn)單易用的?Android?ViewModel?Retrofit框架_Android
- 2022-08-22 PyCharm安裝庫(kù)numpy失敗問(wèn)題的詳細(xì)解決方法_python
- 2023-03-23 React?Native中WebView與html雙向通信遇到的坑_React
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支