一文搞懂Golang中的指針
Golang中和指針相關(guān)的類型有三種:普通指針類型(取地址"&"、指針間接引用"*"), uintptr類型, unsafe.Pointer類型。
普通指針
普通指針類型(取地址"&"、指針間接引用"*"),用于傳遞對(duì)象地址,不能進(jìn)行指針運(yùn)算。Golang會(huì)在編譯時(shí)檢查指針的類型安全性,幫助用戶避免潛在的指針問(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類型
uintptr是一種無(wú)符號(hào)整型類型,可以保存一個(gè)指針值,也可以進(jìn)行指針運(yùn)算,但是它并不是一個(gè)指針類型,所以不能直接用來(lái)取值。想要取值的話,需要通過(guò)unsafe.Pointer轉(zhuǎn)換到具體類型指針后,使用"*"號(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ù)大小的整型類型。
使用示例:
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類型
unsafe.Pointer是unsafe包中的一個(gè)類型,用于處理指針的底層操作??梢詫⑷魏晤愋偷闹羔樲D(zhuǎn)換為unsafe.Pointer類型,也可以將unsafe.Pointer類型轉(zhuǎn)換為任何類型的指針。使用unsafe.Pointer要特別小心,因?yàn)樗鼤?huì)忽略類型安全檢查,可能會(huì)導(dǎo)致內(nèi)存問(wèn)題。
unsafe.Pointer可以作為橋梁,將使用"&"取的地址轉(zhuǎn)換成uintptr進(jìn)行指針運(yùn)算,也可以再轉(zhuǎn)換為具體類型的指針通過(guò)”*“取值。
unsafe.Pointer的四種操作規(guī)則如下:
- 任何類型的指針都可以轉(zhuǎn)化成unsafe.Pointer。
- unsafe.Pointer可以轉(zhuǎn)化成任何類型的指針。
- 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類型的ptr1轉(zhuǎn)換為了*int64類型的ptr2,然后對(duì)*int64進(jìn)行操作,改變了i的值。
小結(jié)
本文介紹了普通指針類型、uintptr類型和unsafe.Pointer類以及它們之間的關(guān)系,官方不推薦使用unsafe 包,因?yàn)樗鼤?huì)忽略類型安全檢查,可能會(huì)導(dǎo)致內(nèi)存問(wèn)題。