指針,或者說pointer是一串指向某個內(nèi)存地址的字符串,所謂指向是指這串字符串的內(nèi)容是內(nèi)存地址的值

10年積累的成都網(wǎng)站制作、網(wǎng)站建設經(jīng)驗,可以快速應對客戶對網(wǎng)站的新想法和需求。提供各種問題對應的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡服務。我雖然不認識你,你也不認識我。但先網(wǎng)站設計后付款的網(wǎng)站建設流程,更有南崗免費網(wǎng)站建設讓你可以放心的選擇與我們合作。
表示取地址,例如你有一個變量a那么a就是變量a在內(nèi)存中的地址,對于golang,指針也是有類型的,比如如果a是一個string那么a是一個string的指針類型,在go里面叫string
所以你看到b := a,a,b是兩個不同的變量,a是string類型,b是string類型,你用fmt去打印b,你會發(fā)現(xiàn)它是一串內(nèi)存地址,而非a的值
所以為了拿到a的值,有個操作*,用來取出指針對應內(nèi)存地址里存的值,所以當你fmt打印一下*b它會跟a一模一樣
tips: *號,可以指向指針類型內(nèi)存地址上的值,號,可以獲取值類型的內(nèi)存地址
每一個變量都有內(nèi)存地址,可以通過變量來操作內(nèi)存地址中的值,即內(nèi)存的大小
go語言中獲取變量的內(nèi)存地址方法:通過 符號可以獲取變量的地址
定義:普通變量存儲的是對應類型的值,這些類型就叫值類型
變量b,在內(nèi)存中的地址為:0x1040a124,在這個內(nèi)存地址上存儲的值為:156
定義:指針類型的變量存儲的是?個地址,所以?叫指針類型或引?類型
b 是值類型,它指向的是內(nèi)存地址上的值
a是指針類型,它指向的是b的內(nèi)存地址
指針類型定義,語法: var 變量名 *類型
指針類型在定義完成后,默認為空地址,即空指針(nil)
在定義好指針變量后,可以通過***** 符號可以獲取指針變量指向的變量
在這里的 *a 等價于 b,通過修改 *a ,最終修改的是值類型b的值
這里a,d是值類型,b,c是指針類型
d就相當于把a內(nèi)存地址上值,在內(nèi)存中從新開辟了一塊空間存儲,d和a互不影響
b,c相當于指向了a的內(nèi)存地址,當使用*號引用出內(nèi)存地址上的變量上,修改值得,a的值也會跟著改變
go語言中的指針和地址值,在使用上常常具有迷惑性,主要是其特殊的*、符號的使用,可能會讓你摸不透,本文希望能講清楚go語言的指針(pointer)和值(value)。
這里先簡單的對指針和地址值概念做一個定義:
這是因為go方法傳遞參數(shù)的方式導致的,go方法函數(shù)傳遞參數(shù)傳遞的是一個拷貝,看看下面的程序會輸出什么?
答案是8,而不是9,因為AddAge函數(shù)修改的是學生的一個備份,而不是原始的學生對象
如果你想正確的給學生年齡增加的話,函數(shù)傳遞的需要是這個值的指針,如下所示:
需要注意的是,這里我們的指針傳遞的仍然是一個拷貝,比如,如果你將s賦值給另外一個指針地址,不會影響原有的指針,這點可以自行實踐下。
那在使用go語言開發(fā)的時候,何時該用指針何時改用地址值呢?比如考慮以下場景:
簡單原則: 當你不確定該使用哪種的時候,優(yōu)先使用指針
如果考慮在數(shù)組、切片、map等復合對象中使用指針和值,比如:
很多開發(fā)者會認為b會更高效,但是被傳遞的都是一個切片的拷貝,切片本身就是一個引用,所以這里被傳遞的其實沒有什么區(qū)別。
對于指針和地址值的使用,大家需要牢記的一點就是go數(shù)據(jù)傳遞的不可變性,活學活用此特點,在無狀態(tài)函數(shù)中此特性非常有用。
不知道你有沒有聽過這么一句:在使用 map 時盡量不要在 big map 中保存指針。好吧,你現(xiàn)在已經(jīng)聽過了:)為什么呢?原因在于 Go 語言的垃圾回收器會掃描標記 map 中的所有元素,GC 開銷相當大,直接GG。
這兩天在《Mastering Go》中看到 GC 這一章節(jié)里面對比 map 和 slice 在垃圾回收中的效率對比,書中只給出結(jié)論沒有說明理由,這我是不能忍的,于是有了這篇學習筆記。扯那么多,Show Your Code
這是一個簡單的測試程序,保存字符串的 map 和 保存整形的 map GC 的效率相差幾十倍,是不是有同學會說明明保存的是 string 哪有指針?這個要說到 Go 語言中 string 的底層實現(xiàn)了,源碼在 src/runtime/string.go里,可以看到 string 其實包含一個指向數(shù)據(jù)的指針和一個長度字段。注意這里的是否包含指針,包括底層的實現(xiàn)。
Go 語言的 GC 會遞歸遍歷并標記所有可觸達的對象,標記完成之后將所有沒有引用的對象進行清理。掃描到指針就會往下接著尋找,一直到結(jié)束。
Go 語言中 map 是基于 數(shù)組和鏈表 的數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的,通過 優(yōu)化的拉鏈法 解決哈希沖突,每個 bucket 可以保存 8 對鍵值,在 8 個鍵值對數(shù)據(jù)后面有一個 overflow 指針,因為桶中最多只能裝 8 個鍵值對,如果有多余的鍵值對落到了當前桶,那么就需要再構(gòu)建一個桶(稱為溢出桶),通過 overflow 指針鏈接起來。
因為 overflow 指針的緣故,所以無論 map 保存的是什么,GC 的時候就會把所有的 bmap 掃描一遍,帶來巨大的 GC 開銷。官方 issues 就有關(guān)于這個問題的討論, runtime: Large maps cause significant GC pauses #9477
無腦機翻如下:
如果我們有一個map [k] v,其中k和v都不包含指針,并且我們想提高掃描性能,則可以執(zhí)行以下操作。
將“ allOverflow [] unsafe.Pointer”添加到 hmap 并將所有溢出存儲桶存儲在其中。 然后將 bmap 標記為noScan。 這將使掃描非常快,因為我們不會掃描任何用戶數(shù)據(jù)。
實際上,它將有些復雜,因為我們需要從allOverflow中刪除舊的溢出桶。 而且它還會增加 hmap 的大小,因此也可能需要重新整理數(shù)據(jù)。
最終官方在 hmap 中增加了 overflow 相關(guān)字段完成了上面的優(yōu)化,這是具體的 commit 地址。
下面看下具體是如何實現(xiàn)的,源碼基于 go1.15,src/cmd/compile/internal/gc/reflect.go 中
通過注釋可以看出,如果 map 中保存的鍵值都不包含指針(通過 Haspointers 判斷),就使用一個 uintptr 類型代替 bucket 的指針用于溢出桶 overflow 字段,uintptr 類型在 GO 語言中就是個大小可以保存得下指針的整數(shù),不是指針,就相當于實現(xiàn)了 將 bmap 標記為 noScan, GC 的時候就不會遍歷完整個 map 了。隨著不斷的學習,愈發(fā)感慨 GO 語言中很多模塊設計得太精妙了。
差不多說清楚了,能力有限,有不對的地方歡迎留言討論,源碼位置還是問的群里大佬 _
如果該函數(shù)會修改receiver,此時一定要用指針
如果receiver是 struct 并且包含互斥類型 sync.Mutex ,或者是類似的同步變量,receiver必須是指針,這樣可以避免對象拷貝
如果receiver是較大的 struct 或者 array ,使用指針則更加高效。多大才算大?假設struct內(nèi)所有成員都要作為函數(shù)變量傳進去,如果覺得這時數(shù)據(jù)太多,就是struct太大
如果receiver是 struct , array 或者 slice ,并且其中某個element指向了某個可變量,則這個時候receiver選指針會使代碼的意圖更加明顯
如果receiver使較小的 struct 或者 array ,并且其變量都是些不變量、常量,例如 time.Time ,value receiver更加適合,因為value receiver可以減少需要回收的垃圾量。
golang的指針receiver和非指針receiver的區(qū)別?
最大的區(qū)別應該是指針傳遞的是對像的引用,這樣在方法里操作的時候可以動態(tài)修改對像的屬性值。
非指針傳遞的是對像的拷貝。
這個應該和PHP的引用的用法差不多。
package?main??
import?(??
"fmt"??
)??
type?Person?struct?{??
Name?string??
Age??int??
}??
func?(p?*Person)?SayHi1()?{??
p.Name?=?"leon1"??
}??
func?(p?Person)?SayHi2()?{??
p.Name?=?"leon2"??
}??
func?main()?{??
p1?:=?Person{Name:?"test",?Age:?10}??
fmt.Println("name1?:?"?+?p1.Name)??
p1.SayHi1()??
fmt.Println("name2?:?"?+?p1.Name)??
p2?:=?Person{Name:?"test1",?Age:?11}??
fmt.Println("name3:?"?+?p2.Name)??
p2.SayHi2()??
fmt.Println("name4?:?"?+?p2.Name)??
}
name1?:?test??
name2?:?leon1??
name3:?test1??
name4?:?test1
標題名稱:go語言里的指針,go語言里的指針是什么
網(wǎng)址分享:http://chinadenli.net/article33/dsshsss.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、動態(tài)網(wǎng)站、網(wǎng)站設計公司、商城網(wǎng)站、定制開發(fā)、域名注冊
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)