一文搞懂Golang中的指針
Golang中和指針相關(guān)的類(lèi)型有三種:普通指針類(lèi)型(取地址"&"、指針間接引用"*"), uintptr類(lèi)型, unsafe.Pointer類(lèi)型。
普通指針
普通指針類(lèi)型(取地址"&"、指針間接引用"*"),用于傳遞對(duì)象地址,不能進(jìn)行指針運(yùn)算。Golang會(huì)在編譯時(shí)檢查指針的類(lèi)型安全性,幫助用戶(hù)避免潛在的指針問(wèn)題。
package main
import "fmt"
type User struct {
Name string
}
func main() {
var u User
u.Name = "xiaoming"
p := &u
fmt.Println(p)
fmt.Println(*p)
}
uintptr類(lèi)型
uintptr是一種無(wú)符號(hào)整型類(lèi)型,可以保存一個(gè)指針值,也可以進(jìn)行指針運(yùn)算,但是它并不是一個(gè)指針類(lèi)型,所以不能直接用來(lái)取值。想要取值的話,需要通過(guò)unsafe.Pointer轉(zhuǎn)換到具體類(lèi)型指針后,使用"*"號(hào)取值。
uintptr在builtin包里的源代碼如下:
// uintptr is an integer type that is large enough to hold the bit pattern of
// any pointer.
type uintptr uintptr
官方的注釋是:uintptr是一個(gè)能足夠容納指針位數(shù)大小的整型類(lèi)型。
使用示例:
package main
import (
"fmt"
"unsafe"
)
func main() {
var num int = 10
ptr := &num
addr := uintptr(unsafe.Pointer(ptr))
fmt.Printf("Value: %v, Address: %v\n", *ptr, addr)
newAddr := addr + 4
newPtr := (*int)(unsafe.Pointer(newAddr))
fmt.Printf("Value: %v, Address: %v\n", *newPtr, newAddr)
}
unsafe.Pointer類(lèi)型
unsafe.Pointer是unsafe包中的一個(gè)類(lèi)型,用于處理指針的底層操作。可以將任何類(lèi)型的指針轉(zhuǎn)換為unsafe.Pointer類(lèi)型,也可以將unsafe.Pointer類(lèi)型轉(zhuǎn)換為任何類(lèi)型的指針。使用unsafe.Pointer要特別小心,因?yàn)樗鼤?huì)忽略類(lèi)型安全檢查,可能會(huì)導(dǎo)致內(nèi)存問(wèn)題。
unsafe.Pointer可以作為橋梁,將使用"&"取的地址轉(zhuǎn)換成uintptr進(jìn)行指針運(yùn)算,也可以再轉(zhuǎn)換為具體類(lèi)型的指針通過(guò)”*“取值。
unsafe.Pointer的四種操作規(guī)則如下:
- 任何類(lèi)型的指針都可以轉(zhuǎn)化成unsafe.Pointer。
- unsafe.Pointer可以轉(zhuǎn)化成任何類(lèi)型的指針。
- uintptr可以轉(zhuǎn)換為unsafe.Pointer。
- unsafeP.ointer可以轉(zhuǎn)換為uintptr。
package main
import (
"fmt"
"unsafe"
)
func main() {
i := 30
ptr1 := &i
var ptr2 *int64 = (*int64)(unsafe.Pointer(ptr1))
*ptr2 = 8
fmt.Println(i)
}
上面的代碼通過(guò)unsafe.Pointer把*int類(lèi)型的ptr1轉(zhuǎn)換為了*int64類(lèi)型的ptr2,然后對(duì)*int64進(jìn)行操作,改變了i的值。
小結(jié)
本文介紹了普通指針類(lèi)型、uintptr類(lèi)型和unsafe.Pointer類(lèi)以及它們之間的關(guān)系,官方不推薦使用unsafe 包,因?yàn)樗鼤?huì)忽略類(lèi)型安全檢查,可能會(huì)導(dǎo)致內(nèi)存問(wèn)題。