Go語言里面的指針和C++指針一樣,都是指向某塊內(nèi)存的地址值,可以解引用,不同只是在于C++里可以直接對指針做算術(shù)運(yùn)算而Go里面不行。
創(chuàng)新互聯(lián)企業(yè)建站,十年網(wǎng)站建設(shè)經(jīng)驗(yàn),專注于網(wǎng)站建設(shè)技術(shù),精于網(wǎng)頁設(shè)計(jì),有多年建站和網(wǎng)站代運(yùn)營經(jīng)驗(yàn),設(shè)計(jì)師為客戶打造網(wǎng)絡(luò)企業(yè)風(fēng)格,提供周到的建站售前咨詢和貼心的售后服務(wù)。對于網(wǎng)站建設(shè)、網(wǎng)站制作中不同領(lǐng)域進(jìn)行深入了解和探索,創(chuàng)新互聯(lián)在網(wǎng)站建設(shè)中充分了解客戶行業(yè)的需求,以靈動的思維在網(wǎng)頁中充分展現(xiàn),通過對客戶行業(yè)精準(zhǔn)市場調(diào)研,為客戶提供的解決方案。
本文介紹一些Go語言的基礎(chǔ)語法。
先來看一個簡單的go語言代碼:
go語言的注釋方法:
代碼執(zhí)行結(jié)果:
下面來進(jìn)一步介紹go的基礎(chǔ)語法。
go語言中格式化輸出可以使用 fmt 和 log 這兩個標(biāo)準(zhǔn)庫,
常用方法:
示例代碼:
執(zhí)行結(jié)果:
更多格式化方法可以訪問中的fmt包。
log包實(shí)現(xiàn)了簡單的日志服務(wù),也提供了一些格式化輸出的方法。
執(zhí)行結(jié)果:
下面來介紹一下go的數(shù)據(jù)類型
下表列出了go語言的數(shù)據(jù)類型:
int、float、bool、string、數(shù)組和struct屬于值類型,這些類型的變量直接指向存在內(nèi)存中的值;slice、map、chan、pointer等是引用類型,存儲的是一個地址,這個地址存儲最終的值。
常量是在程序編譯時就確定下來的值,程序運(yùn)行時無法改變。
執(zhí)行結(jié)果:
執(zhí)行結(jié)果:
Go 語言的運(yùn)算符主要包括算術(shù)運(yùn)算符、關(guān)系運(yùn)算符、邏輯運(yùn)算符、位運(yùn)算符、賦值運(yùn)算符以及指針相關(guān)運(yùn)算符。
算術(shù)運(yùn)算符:
關(guān)系運(yùn)算符:
邏輯運(yùn)算符:
位運(yùn)算符:
賦值運(yùn)算符:
指針相關(guān)運(yùn)算符:
下面介紹一下go語言中的if語句和switch語句。另外還有一種控制語句叫select語句,通常與通道聯(lián)用,這里不做介紹。
if語法格式如下:
if ... else :
else if:
示例代碼:
語法格式:
另外,添加 fallthrough 會強(qiáng)制執(zhí)行后面的 case 語句,不管下一條case語句是否為true。
示例代碼:
執(zhí)行結(jié)果:
下面介紹幾種循環(huán)語句:
執(zhí)行結(jié)果:
執(zhí)行結(jié)果:
也可以通過標(biāo)記退出循環(huán):
--THE END--
不知道你有沒有聽過這么一句:在使用 map 時盡量不要在 big map 中保存指針。好吧,你現(xiàn)在已經(jīng)聽過了:)為什么呢?原因在于 Go 語言的垃圾回收器會掃描標(biāo)記 map 中的所有元素,GC 開銷相當(dāng)大,直接GG。
這兩天在《Mastering Go》中看到 GC 這一章節(jié)里面對比 map 和 slice 在垃圾回收中的效率對比,書中只給出結(jié)論沒有說明理由,這我是不能忍的,于是有了這篇學(xué)習(xí)筆記。扯那么多,Show Your Code
這是一個簡單的測試程序,保存字符串的 map 和 保存整形的 map GC 的效率相差幾十倍,是不是有同學(xué)會說明明保存的是 string 哪有指針?這個要說到 Go 語言中 string 的底層實(shí)現(xiàn)了,源碼在 src/runtime/string.go里,可以看到 string 其實(shí)包含一個指向數(shù)據(jù)的指針和一個長度字段。注意這里的是否包含指針,包括底層的實(shí)現(xiàn)。
Go 語言的 GC 會遞歸遍歷并標(biāo)記所有可觸達(dá)的對象,標(biāo)記完成之后將所有沒有引用的對象進(jìn)行清理。掃描到指針就會往下接著尋找,一直到結(jié)束。
Go 語言中 map 是基于 數(shù)組和鏈表 的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,通過 優(yōu)化的拉鏈法 解決哈希沖突,每個 bucket 可以保存 8 對鍵值,在 8 個鍵值對數(shù)據(jù)后面有一個 overflow 指針,因?yàn)橥爸凶疃嘀荒苎b 8 個鍵值對,如果有多余的鍵值對落到了當(dāng)前桶,那么就需要再構(gòu)建一個桶(稱為溢出桶),通過 overflow 指針鏈接起來。
因?yàn)?overflow 指針的緣故,所以無論 map 保存的是什么,GC 的時候就會把所有的 bmap 掃描一遍,帶來巨大的 GC 開銷。官方 issues 就有關(guān)于這個問題的討論, runtime: Large maps cause significant GC pauses #9477
無腦機(jī)翻如下:
如果我們有一個map [k] v,其中k和v都不包含指針,并且我們想提高掃描性能,則可以執(zhí)行以下操作。
將“ allOverflow [] unsafe.Pointer”添加到 hmap 并將所有溢出存儲桶存儲在其中。 然后將 bmap 標(biāo)記為noScan。 這將使掃描非???,因?yàn)槲覀儾粫呙枞魏斡脩魯?shù)據(jù)。
實(shí)際上,它將有些復(fù)雜,因?yàn)槲覀冃枰獜腶llOverflow中刪除舊的溢出桶。 而且它還會增加 hmap 的大小,因此也可能需要重新整理數(shù)據(jù)。
最終官方在 hmap 中增加了 overflow 相關(guān)字段完成了上面的優(yōu)化,這是具體的 commit 地址。
下面看下具體是如何實(shí)現(xiàn)的,源碼基于 go1.15,src/cmd/compile/internal/gc/reflect.go 中
通過注釋可以看出,如果 map 中保存的鍵值都不包含指針(通過 Haspointers 判斷),就使用一個 uintptr 類型代替 bucket 的指針用于溢出桶 overflow 字段,uintptr 類型在 GO 語言中就是個大小可以保存得下指針的整數(shù),不是指針,就相當(dāng)于實(shí)現(xiàn)了 將 bmap 標(biāo)記為 noScan, GC 的時候就不會遍歷完整個 map 了。隨著不斷的學(xué)習(xí),愈發(fā)感慨 GO 語言中很多模塊設(shè)計(jì)得太精妙了。
差不多說清楚了,能力有限,有不對的地方歡迎留言討論,源碼位置還是問的群里大佬 _
tips: *號,可以指向指針類型內(nèi)存地址上的值,號,可以獲取值類型的內(nèi)存地址
每一個變量都有內(nèi)存地址,可以通過變量來操作內(nèi)存地址中的值,即內(nèi)存的大小
go語言中獲取變量的內(nèi)存地址方法:通過 符號可以獲取變量的地址
定義:普通變量存儲的是對應(yīng)類型的值,這些類型就叫值類型
變量b,在內(nèi)存中的地址為:0x1040a124,在這個內(nèi)存地址上存儲的值為:156
定義:指針類型的變量存儲的是?個地址,所以?叫指針類型或引?類型
b 是值類型,它指向的是內(nèi)存地址上的值
a是指針類型,它指向的是b的內(nèi)存地址
指針類型定義,語法: var 變量名 *類型
指針類型在定義完成后,默認(rèn)為空地址,即空指針(nil)
在定義好指針變量后,可以通過***** 符號可以獲取指針變量指向的變量
在這里的 *a 等價于 b,通過修改 *a ,最終修改的是值類型b的值
這里a,d是值類型,b,c是指針類型
d就相當(dāng)于把a(bǔ)內(nèi)存地址上值,在內(nèi)存中從新開辟了一塊空間存儲,d和a互不影響
b,c相當(dāng)于指向了a的內(nèi)存地址,當(dāng)使用*號引用出內(nèi)存地址上的變量上,修改值得,a的值也會跟著改變
如果該函數(shù)會修改receiver,此時一定要用指針
如果receiver是 struct 并且包含互斥類型 sync.Mutex ,或者是類似的同步變量,receiver必須是指針,這樣可以避免對象拷貝
如果receiver是較大的 struct 或者 array ,使用指針則更加高效。多大才算大?假設(shè)struct內(nèi)所有成員都要作為函數(shù)變量傳進(jìn)去,如果覺得這時數(shù)據(jù)太多,就是struct太大
如果receiver是 struct , array 或者 slice ,并且其中某個element指向了某個可變量,則這個時候receiver選指針會使代碼的意圖更加明顯
如果receiver使較小的 struct 或者 array ,并且其變量都是些不變量、常量,例如 time.Time ,value receiver更加適合,因?yàn)関alue receiver可以減少需要回收的垃圾量。
以下代碼在VC6.0以上版本測試通過!
輸出結(jié)果:6
#include stdio.h
int main(void)
{
int a[2][2] = {{1,2}, {3,4}};
int b[2][2] = {{5,6}, {7,8}};
int (*p1)[2] = a;
int (*p2)[2] = b;
int (*q[2])[2] = {p1, p2}; 這樣才是正確的定義!
printf("%d\n", *(*q[1]+1));
return 0;
}
但在tc2.0和bc3.1中提示非法初始化!
但把
int (*q[2])[2] = {p1, p2};
改成
int (*q[2])[2];
q[0] = p1;
q[1] = p2;
可以通過!
原因暫不清楚,估計(jì)是老舊的編譯器不支持太復(fù)雜的定義!
其實(shí)最好的方法是使用typedef,簡單明了,可讀性大大提升!
#include stdio.h
int main(void)
{
typedef int (*PA)[2]; 使用typedef
int a[2][2] = {{1,2}, {3,4}};
int b[2][2] = {{5,6}, {7,8}};
int (*p1)[2] = a;
int (*p2)[2] = b;
PA q[2]= {p1, p2}; 這樣可讀性是否大大的增加?!
printf("%d\n", *(*q[1]+1));
return 0;
}
網(wǎng)頁名稱:go語言輸出存放指針,go語言的指針
網(wǎng)站地址:http://muchs.cn/article14/hcgdge.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站排名、品牌網(wǎng)站制作、域名注冊、定制開發(fā)、標(biāo)簽優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)