Go指針和unsafe.Pointer有什麼區別

Go 語言的作者之一 Ken Thompson 也是 C 語言的作者。所以,Go 可以看作 C 系語言,它的很多特性都和 C 類似,指針就是其中之一。

然而,Go 語言的指針相比 C 的指針有很多限制。這當然是爲了安全考慮,要知道像 Java/Python 這些現代語言,生怕程序員出錯,哪有什麼指針(這裏指的是顯式的指針)?更別說像 C/C++ 還需要程序員自己清理“垃圾”。所以對於 Go 來說,有指針已經很不錯了,僅管它有很多限制。

相比於 C 語言中指針的靈活,Go 的指針多了一些限制。但這也算是 Go 的成功之處:既可以享受指針帶來的便利,又避免了指針的危險性。

限制一:Go 的指針不能進行數學運算

來看一個簡單的例子:

a := 5
p := &a

p++
p = &a + 3

上面的代碼將不能通過編譯,會報編譯錯誤:invalid operation,也就是說不能對指針做數學運算。

限制二:不同類型的指針不能相互轉換

例如下面這個簡短的例子:

func main() {
	a := int(100)
	var f *float64
	
	f = &a
}

也會報編譯錯誤:

cannot use &a (type *int) as type *float64 in assignment

限制三:不同類型的指針不能使用 == 或 != 比較

只有在兩個指針類型相同或者可以相互轉換的情況下,纔可以對兩者進行比較。另外,指針可以通過 ==!= 直接和 nil 作比較。

限制四:不同類型的指針變量不能相互賦值

這一點同限制三。

unsafe.Pointer 在 unsafe 包:

type ArbitraryType int

type Pointer *ArbitraryType

從命名來看,Arbitrary 是任意的意思,也就是說 Pointer 可以指向任意類型,實際上它類似於 C 語言裏的 void*

unsafe 包提供了 2 點重要的能力:

  1. 任何類型的指針和 unsafe.Pointer 可以相互轉換。
  2. uintptr 類型和 unsafe.Pointer 可以相互轉換。

type pointer uintptr

pointer 不能直接進行數學運算,但可以把它轉換成 uintptr,對 uintptr 類型進行數學運算,再轉換成 pointer 類型。

// uintptr 是一個整數類型,它足夠大,可以存儲
type uintptr uintptr

還有一點要注意的是,uintptr 並沒有指針的語義,意思就是 uintptr 所指向的對象會被 gc 無情地回收。而 unsafe.Pointer 有指針語義,可以保護它所指向的對象在“有用”的時候不會被垃圾回收。

unsafe 包中的幾個函數都是在編譯期間執行完畢,畢竟,編譯器對內存分配這些操作“瞭然於胸”。在 /usr/local/go/src/cmd/compile/internal/gc/unsafe.go 路徑下,可以看到編譯期間 Go 對 unsafe 包中函數的處理。

轉載出處,轉載爲了記錄學習

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章