go語言沒有指標運算。go語言的語法上是不支援指標運算的,所有指標都在可控的一個範圍內使用;但實際上,go語言可以通過unsafe包的Pointer()方法把指標轉換為uintptr型別的數位,來間接實現指標運算。
本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。
記憶體就是一系列有序列號的儲存單元,變數就是編譯器為記憶體地址分配的暱稱,那麼指標是什麼呢?
指標就是一個指向另一個記憶體地址變數的值
指標指向變數的記憶體地址,指標就像該變數值的記憶體地址一樣
我們來看一個程式碼片段
func main() {
a := 200
b := &a
*b++
fmt.Println(a)
}
登入後複製
在 main 函數的第一行,我們定義了一個新的變數 a ,並賦值為 200。接下來我們定義了一個變數 b ,並將變數 a 的地址賦值給 b 。我們並不知道 a 的準確儲存地址,但是我們依然可以將 a 的地址儲存在變數 b 中。
因為 Go 強型別的特性,第三行程式碼也許是最具干擾性的了,b 包含 a 變數的地址,但是我們想增加儲存在 a 變數中的值。
這樣我們必須取消參照 b ,而是跟隨指標由 b 參照 a。
然後我們將該值加 1 後,儲存回 b 中儲存的記憶體地址上。
最後一行列印了 a 的值,可以看到 a 的值已經增加為了 201
Go語言中的函數傳參都是值拷貝,當我們想要修改某個變數的時候,我們可以建立一個指向該變數地址的指標變數。
區別於C/C++中的指標,Go語言中的指標不能進行偏移和運算,是安全指標。
要搞明白Go語言中的指標需要先知道3個概念:指標地址、指標型別和指標取值。
Go語言中的指標操作非常簡單,只需要記住兩個符號:&(取地址)和*(根據地址取值)。
每個變數在執行時都擁有一個地址,這個地址代表變數在記憶體中的位置。Go語言中使用&字元放在變數前面對變數進行「取地址」操作。
取變數指標的語法如下:
ptr := &v // v的型別為T
登入後複製
其中:
v:代表被取地址的變數,型別為T
ptr:用於接收地址的變數,ptr的型別就為*T,稱做T的指標型別。*代表指標。
func main() {
a := 10
b := &a
fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078
fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int
fmt.Println(&b) // 0xc00000e018
}
登入後複製
1.指標運運算元為左值時,我們可以更新目標物件的狀態;而為右值時則是為了獲取目標的狀態。
func main() {
x := 10
var p *int = &x //獲取地址,儲存到指標變數
*p += 20 //用指標間接參照,並更新物件
println(p, *p) //輸出指標所儲存的地址,以及目標物件
}
登入後複製
輸出:
0xc000040780 30
登入後複製
2.指標型別支援相等運運算元,但不能做加減運算和型別轉換。如果兩個指標指向同一地址,或都為nil,那麼它們相等。
func main() {
x := 10
p := &x
p++ //編譯報錯 invalid operation: p++ (non-numeric type *int)
var p2 *int = p+1 //invalid operation: p + 1 (mismatched types *int and int)
p2 = &x
println(p == p2) //指向同一地址
}
登入後複製
可通過unsafe.Pointer將指標轉換為uintptr後進行加減法運算,但可能會造成非法存取。
在很多 golang 程式中,雖然用到了指標,但是並不會對指標進行加減運算,這和 C 程式是很不一樣的。Golang 的官方入門學習工具() 甚至說 Go 不支援指標算術。雖然實際上並不是這樣的,但我在一般的 go 程式中,好像確實沒見過指標運算(嗯,我知道你想寫不一般的程式)。
- 但實際上,go 可以通過
unsafe.Pointer
來把指標轉換為uintptr
型別的數位,來間接實現指標運算。- 這裡請注意,
uintptr
是一種整數型別,而不是指標型別。
比如:
uintptr(unsafe.Pointer(&p)) + 1
登入後複製
就得到了 &p
的下一個位元組的位置。然而,根據 《Go Programming Language》 的提示,我們最好直接把這個計算得到的記憶體地址轉換為指標型別:
unsafe.Pointer(uintptr(unsafe.Pointer(&p) + 1))
登入後複製
因為 go 中是有垃圾回收機制的,如果某種 GC 挪動了目標值的記憶體地址,以整型來儲存的指標數值,就成了無效的值。
同時也要注意,go 中對指標的 + 1,真的就只是指向了下一個位元組,而 C 中 + 1
或者 ++
考慮了資料型別的長度,會自動指向當前值結尾後的下一個位元組(或者說,有可能就是下一個值的開始)。如果 go 中要想實現同樣的效果,可以使用 unsafe.Sizeof
方法:
unsafe.Pointer(uintptr(unsafe.Pointer(&p) + unsafe.Sizeof(p)))
登入後複製
最後,另外一種常用的指標操作是轉換指標型別。這也可以利用 unsafe 包來實現:
var a int64 = 1
(*int8)(unsafe.Pointer(&a))
登入後複製
如果你沒有遇到過需要轉換指標型別的需求,可以看看,其中構建 IP 協定首部的程式碼,就用到了指標型別轉換。
【相關推薦:Go視訊教學、】
以上就是go語言中指標有哪些運算的詳細內容,更多請關注TW511.COM其它相關文章!