Go語(yǔ)言快速入門指針Map使用示例教程
1. 指針
區(qū)別于C/C++
中的指針,Go
語(yǔ)言中的指針不能進(jìn)行偏移和運(yùn)算,是安全指針。
要搞明白Go
語(yǔ)言中的指針需要先知道3個(gè)概念:指針地址、指針類型和指針取值。
Go
語(yǔ)言中的函數(shù)傳參都是值拷貝,當(dāng)我們想要修改某個(gè)變量的時(shí)候,我們可以創(chuàng)建一個(gè)指向該變量地址的指針變量。
傳遞數(shù)據(jù)使用指針,而無(wú)須拷貝數(shù)據(jù)。類型指針不能進(jìn)行偏移和運(yùn)算。
Go
語(yǔ)言中的指針操作非常簡(jiǎn)單,只需要記住兩個(gè)符號(hào):&(取地址)和*(根據(jù)地址取值)。
1.1 指針地址和指針類型
每個(gè)變量在運(yùn)行時(shí)都擁有一個(gè)地址,這個(gè)地址代表變量在內(nèi)存中的位置。Go
語(yǔ)言中使用&
字符放在變量前面對(duì)變量進(jìn)行“取地址”操作。
Go
語(yǔ)言中的值類型(int
、float
、bool
、string
、array
、struct
)都有對(duì)應(yīng)的指針類型,如:*int
、*int64
、*string
等。
取變量指針的語(yǔ)法如下:
ptr?:=?&v????//?v的類型為T
其中:
v
:代表被取地址的變量,類型為T
ptr
:用于接收地址的變量,ptr
的類型就為*T
,稱做T
的指針類型。*
代表指針。
package?main import?"fmt" func?main()?{ ????a?:=?10 ????b?:=?&a ????fmt.Printf("a:%d?ptr:%p\n",?a,?&a)?//?a:10?ptr:0xc00001a078 ????fmt.Printf("b:%p?type:%T\n",?b,?b)?//?b:0xc00001a078?type:*int ????fmt.Println(&b)????????????????????//?0xc00000e018 }
1.2 指針取值
在對(duì)普通變量使用&
操作符取地址后會(huì)獲得這個(gè)變量的指針,然后可以對(duì)指針使用*
操作,也就是指針取值。
package?main import?"fmt" func?main()?{ ????//指針取值 ????a?:=?10 ????b?:=?&a?//?取變量a的地址,將指針保存到b中 ????fmt.Printf("type?of?b:?%T\n",?b) ????c?:=?*b?//?指針取值(根據(jù)指針去內(nèi)存取值) ????fmt.Printf("type?of?c:?%T\n",?c) ????fmt.Printf("value?of?c:?%v\n",?c) }
輸出結(jié)果:
type of b: *int
type of c: int
value of c: 10
取地址操作符&
和取值操作符*
是一對(duì)互補(bǔ)操作符,&
取出地址,*
根據(jù)地址取出地址指向的值。
變量、指針地址、指針變量、取地址、取值的相互關(guān)系和特性如下:
- 對(duì)變量進(jìn)行取地址(
&
)操作,可以獲得這個(gè)變量的指針變量。 - 指針變量的值是指針地址。
- 對(duì)指針變量進(jìn)行取值(
*
)操作,可以獲得指針變量指向的原變量的值。
package?main import?"fmt" func?p1(n?int)?{ ????n?=?100 } func?p2(n?*int)?{ ????*n?=?100 } func?main()?{ ????a?:=?10 ????p1(a) ????fmt.Println(a)?//?10 ????p2(&a) ????fmt.Println(a)?//?100 }
1.3 空指針
- 當(dāng)一個(gè)指針被定義后沒(méi)有分配到任何變量時(shí),它的值為
nil
- 空指針的判斷
package?main import?"fmt" func?main()?{ ????var?p?*string ????fmt.Printf("p的值是%v?\n",?p) ????if?p?!=?nil?{ ????????fmt.Println("非空指針") ????}?else?{ ????????fmt.Println("空指針") ????} }
1.4 new 的使用
new
是一個(gè)內(nèi)置的函數(shù),它的函數(shù)簽名如下:
func?new(Type)?*Type
其中:
Type
表示類型,new
函數(shù)只接受一個(gè)參數(shù),這個(gè)參數(shù)是一個(gè)類型*Type
表示類型指針,new
函數(shù)返回一個(gè)指向該類型內(nèi)存地址的指針。
new
函數(shù)不太常用,使用new
函數(shù)得到的是一個(gè)類型的指針,并且該指針對(duì)應(yīng)的值為該類型的零值。
func?main()?{ ????a?:=?new(int) ????b?:=?new(bool) ????fmt.Printf("%T\n",?a)?//?*int ????fmt.Printf("%T\n",?b)?//?*bool ????fmt.Println(*a)???????//?0 ????fmt.Println(*b)???????//?false }
var a *int
只是聲明了一個(gè)指針變量a
但是沒(méi)有初始化,指針作為引用類型需要初始化后才會(huì)擁有內(nèi)存空間,才可以給它賦值。應(yīng)該按照如下方式使用內(nèi)置的new
函數(shù)對(duì)a
進(jìn)行初始化之后就可以正常對(duì)其賦值了:
func?main()?{ ????var?a?*int ????a?=?new(int) ????*a?=?10 ????fmt.Println(*a) }
make
也是用于內(nèi)存分配的,區(qū)別于new
,它只用于slice
、map
以及chan
的內(nèi)存創(chuàng)建,而且它返回的類型就是這三個(gè)類型本身,而不是他們的指針類型,因?yàn)檫@三種類型就是引用類型,所以就沒(méi)有必要返回他們的指針了。
1.5 new與make的區(qū)別
- 二者都是用來(lái)做內(nèi)存分配的。
make
只用于slice
、map
以及channel
的初始化,返回的還是這三個(gè)引用類型本身;- 而
new
用于類型的內(nèi)存分配,并且內(nèi)存對(duì)應(yīng)的值為類型零值,返回的是指向類型的指針。
2. Map
map
是一種無(wú)序的基于key-value的數(shù)據(jù)結(jié)構(gòu),Go語(yǔ)言中的map是引用類型,必須初始化才能使用。
2.1 什么是Map
key,value存儲(chǔ)
最通俗的話說(shuō):Map
是一種通過(guò)key
來(lái)獲取value
的一個(gè)數(shù)據(jù)結(jié)構(gòu),其底層存儲(chǔ)方式為數(shù)組,在存儲(chǔ)時(shí)key
不能重復(fù),當(dāng)key
重復(fù)時(shí),value
進(jìn)行覆蓋,我們通過(guò)key
進(jìn)行hash
運(yùn)算(可以簡(jiǎn)單理解為把key
轉(zhuǎn)化為一個(gè)整形數(shù)字)然后對(duì)數(shù)組的長(zhǎng)度取余,得到key
存儲(chǔ)在數(shù)組的哪個(gè)下標(biāo)位置,最后將key
和value
組裝為一個(gè)結(jié)構(gòu)體,放入數(shù)組下標(biāo)處。
hash沖突
數(shù)組一個(gè)下標(biāo)處只能存儲(chǔ)一個(gè)元素,也就是說(shuō)一個(gè)數(shù)組下標(biāo)只能存儲(chǔ)一對(duì)key
,value
, hashkey(xiaoming)=4
占用了下標(biāo)0的位置,假設(shè)我們遇到另一個(gè)key
,hashkey(xiaowang)
也是4
,這就是hash
沖突(不同的key
經(jīng)過(guò)hash
之后得到的值一樣),那么key=xiaowang
的怎么存儲(chǔ)?
hash沖突的常見解決方法
- 開放定址法: 也就是說(shuō)當(dāng)我們存儲(chǔ)一個(gè)
key
,value
時(shí),發(fā)現(xiàn)hashkey(key)
的下標(biāo)已經(jīng)被別key
占用,那我們?cè)谶@個(gè)數(shù)組中空間中重新找一個(gè)沒(méi)被占用的存儲(chǔ)這個(gè)沖突的key
,那么沒(méi)被占用的有很多,找哪個(gè)好呢?常見的有:線性探測(cè)法,線性補(bǔ)償探測(cè)法,隨機(jī)探測(cè)法,這里以線性探測(cè)為對(duì)比。 - 拉鏈法: 何為拉鏈,簡(jiǎn)單理解為鏈表,當(dāng)
key
的hash
沖突時(shí),我們?cè)跊_突位置的元素上形成一個(gè)鏈表,通過(guò)指針互連接,當(dāng)查找時(shí),發(fā)現(xiàn)key
沖突,順著鏈表一直往下找,直到鏈表的尾節(jié)點(diǎn),找不到則返回空。
開放定址(線性探測(cè))和拉鏈的優(yōu)缺點(diǎn)
- 拉鏈法比線性探測(cè)處理簡(jiǎn)單
- 線性探測(cè)查找是會(huì)被拉鏈法會(huì)更消耗時(shí)間
- 線性探測(cè)會(huì)更加容易導(dǎo)致擴(kuò)容,而拉鏈不會(huì)
- 拉鏈存儲(chǔ)了指針,所以空間上會(huì)比線性探測(cè)占用多一點(diǎn)
- 拉鏈?zhǔn)莿?dòng)態(tài)申請(qǐng)存儲(chǔ)空間的,所以更適合鏈長(zhǎng)不確定的
2.2 Map 定義
Go
語(yǔ)言中 Map
的定義語(yǔ)法如下:
map[KeyType]ValueType
其中:
KeyType
: 表示鍵的類型。ValueType
: 表示鍵對(duì)應(yīng)的值的類型。
map
類型的變量默認(rèn)初始值為nil
,需要使用make()
函數(shù)來(lái)分配內(nèi)存。語(yǔ)法為:
?make(map[KeyType]ValueType,?[cap])
其中cap
表示map
的容量,該參數(shù)雖然不是必須的,但是我們應(yīng)該在初始化map
的時(shí)候就為其指定一個(gè)合適的容量。
2.3 map基本使用
map
中的數(shù)據(jù)都是成對(duì)出現(xiàn)的,map
的基本使用如下:
func?main()?{ ????scoreMap?:=?make(map[string]int,?8) ????scoreMap["張三"]?=?90 ????scoreMap["李四"]?=?100 ????fmt.Println(scoreMap) ????fmt.Println(scoreMap["李四"]) ????fmt.Printf("type?of?a:?%T\n",?scoreMap) }
輸出結(jié)果:
map[李四:100 張三:90]
100
type of a: map[string]int
map
也支持在聲明的時(shí)候填充元素:
func?main()?{ ????userInfo?:=?map[string]string{ ????????"username":?"admin", ????????"password":?"123456", ????} ????fmt.Println(userInfo) }
2.4 map的遍歷
Go
語(yǔ)言中使用for range
遍歷map
:
func?main()?{ ????scoreMap?:=?make(map[string]int) ????scoreMap["張三"]?=?90 ????scoreMap["李四"]?=?100 ????scoreMap["王五"]?=?60 ????for?k,?v?:=?range?scoreMap?{ ????????fmt.Println(k,?v) ????} }
如果只想遍歷key
的時(shí)候,可以按下面的寫法:
func?main()?{ ????scoreMap?:=?make(map[string]int) ????scoreMap["張三"]?=?90 ????scoreMap["李四"]?=?100 ????scoreMap["王五"]?=?60 ????for?k?:=?range?scoreMap?{ ????????fmt.Println(k) ????} }
注意: 遍歷map
時(shí)的元素順序與添加鍵值對(duì)的順序無(wú)關(guān)。
2.5 map判斷某個(gè)鍵是否存在
Go
語(yǔ)言中有個(gè)判斷map
中鍵是否存在的特殊寫法,格式如下:
value,?ok?:=?map[key]
如果key
存在ok
為true
,value
為對(duì)應(yīng)的值;不存在ok
為false
,value
為值類型的零值
func?main()?{ ????scoreMap?:=?make(map[string]int) ????scoreMap["張三"]?=?90 ????scoreMap["李四"]?=?100 ????//?如果key存在ok為true,value為對(duì)應(yīng)的值;不存在ok為false,value為值類型的零值 ????value,?ok?:=?scoreMap["張三"] ????if?ok?{ ????????fmt.Println(v) ????}?else?{ ????????fmt.Println("查無(wú)此人") ????} }
2.6 map使用delete()函數(shù)刪除鍵值對(duì)
使用delete()
內(nèi)建函數(shù)從map
中刪除一組鍵值對(duì), delete()
函數(shù)的格式如下:
delete(map,?key)
其中:
map
: 表示要?jiǎng)h除鍵值對(duì)的map
key
: 表示要?jiǎng)h除的鍵值對(duì)的鍵
func?main(){ ????scoreMap?:=?make(map[string]int) ????scoreMap["張三"]?=?90 ????scoreMap["李四"]?=?100 ????scoreMap["王五"]?=?60 ????delete(scoreMap,?"李四")//將李四:?100從?map?中刪除 ????for?k,v?:=?range?scoreMap{ ????????fmt.Println(k,?v) ????} }
以上就是Go語(yǔ)言快速入門指針Map使用示例教程的詳細(xì)內(nèi)容,更多關(guān)于Go語(yǔ)言入門指針Map教程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決 Golang VS Code 插件下載安裝失敗的問(wèn)題
這篇文章主要介紹了解決 Golang VS Code 插件下載安裝失敗,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05Golang打包go項(xiàng)目部署到linux服務(wù)器正確方法
這篇文章主要給大家介紹了關(guān)于Golang打包go項(xiàng)目部署到linux服務(wù)器的正確方法,Go?是一個(gè)開源的編程語(yǔ)言,它能讓構(gòu)造簡(jiǎn)單、可靠且高效的軟件變得容易,具有簡(jiǎn)潔、快速、安全,并行、有趣、開源,內(nèi)存管理、v數(shù)組安全、編譯迅速的特征,需要的朋友可以參考下2023-10-10Bililive-go 實(shí)現(xiàn)直播自動(dòng)監(jiān)控錄制功能
最近有直播錄制的需求,但是自己手動(dòng)錄制太麻煩繁瑣,于是用了開源項(xiàng)目Bililive-go進(jìn)行全自動(dòng)監(jiān)控錄制,對(duì)Bililive-go 直播自動(dòng)監(jiān)控錄制實(shí)現(xiàn)思路感興趣的朋友,一起看看吧2024-03-03go語(yǔ)言中http超時(shí)引發(fā)的事故解決
我們使用的是golang標(biāo)準(zhǔn)庫(kù)的http client,對(duì)于一些http請(qǐng)求,我們?cè)谔幚淼臅r(shí)候,會(huì)考慮加上超時(shí)時(shí)間,如果超時(shí)可能會(huì)引起報(bào)錯(cuò),本文就記一次超時(shí)引發(fā)的事故2021-06-06在Go中實(shí)現(xiàn)和使用堆棧以及先進(jìn)先出原則詳解
Go是一種功能強(qiáng)大的編程語(yǔ)言,提供了豐富的數(shù)據(jù)結(jié)構(gòu)和算法,堆棧是計(jì)算機(jī)科學(xué)中的基本數(shù)據(jù)結(jié)構(gòu)之一,在本博文中,我們將探討如何在?Go?中實(shí)現(xiàn)和使用堆棧,以及堆棧如何遵循先進(jìn)先出?(FIFO)?原則2023-10-10一篇文章說(shuō)清楚?go?get?使用私有庫(kù)的方法
這篇文章主要介紹了go?get?如何使用私有庫(kù),本文會(huì)明確指出Git?、golang的配置項(xiàng),附送TortoiseGit?+?Git混合配置,需要的朋友可以參考下2022-09-09