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其中:
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後進行加減法運算,但可能會造成非法存取。
go tour) 甚至說 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語言中指針有哪些運算的詳細內容。更多資訊請關注PHP中文網其他相關文章!