看完這個,我徹底理解了Golang的指針
golang中一個非常鮮明的特點就是引入了指針的使用,這個在py、php、java中都是不支持的,但是很多讀者都反饋說對指針不是很了解,所以今天寫了這篇文章,當然我盡量用通俗的語言,希望對您有用。
什么是指針
想了解什么是指針,你先得了解數據是怎么取到的
上述代碼非常簡單,我相信不會golang的讀者應該也能看懂。但是他底層究竟干嘛了?你真的了解過么?接下來咱們逐一解釋
首先這一步,是給變量a,在內存中開辟了一塊空間,因為是int類型,所以空間大小為4個字節,那么問題來了,「這塊空間開在內存哪個位置?」 首先這塊位置是系統「隨機分配」的一塊。另外給這塊內存做了一個「標記」,方便下次找到,「這個標記就在這塊內存的起始的位置」
接下來給變量a賦值為1。那么系統如何賦值的呢?首先總得找到a這塊內存在哪吧?「如何找到給a分配的那塊內存的呢?」當然是通過之前給a變量做的那個「標記」。通過標記找到這塊內存所在的位置,然后直接在開辟好的內存空間存下給a賦值的數據就可以了。
這段代碼,我們暫且先不用去了解fmt.Println是怎么實現的,只用關心a是怎么取到的,當然是先「找到a之前所做的那個標記」,找到對應的內存所在的位置,直接往后偏移4個位置把值取出來就行。
這下是不是感覺清晰明了了?
我們在上述過程中,所說的「標記」,就是「指針」.所以指針其實就是一個「標記數據所在位置的數據類型而已」,只不過他有一些自己特殊的語法而已,而且是一種新的數據類型。這么來看,就很簡單了。
指針的定義
指針是一種「數據類型」,用于表示數據的「內存地址」。
如何使用指針
我們來看下面幾個例子感受一下
case1
注意:
- 聲明指針的類型,只需要在前面加上一個*就可以了,這是固定的語法
- 不管什么指針類型(*int, *string, *float),初始值都為nil
case2
注意
- 取變量name的首地址,也就是指針的值,需要用&name表示,而取出來的值也只能用指針這種變量類型來保存,所以var p_name *string = &name這段代碼是合理的
- p_name的具體值是隨機分配的一個16進制的值,0x14000010240,知道這個代表的是指針的值就行了,因為是隨機分配的,所以不同設備是不一樣的。
- 要取一個指針類型指向的具體值,用 * (對應的指針類型的變量名)就能直接取到,比如上面的例子,「對應的指針類型的變量名為p_name,所以用*p_name就能直接取到指針p_name所指向的具體值」。
說明
上面我們通過&name獲取到了name的內存空間的地址是0x14000010240,p_name的變量的值實際上是name變量的內存空間的值,p_name也是一個變量 那么p_name變量所存放值的地方,是不是也會有一個內存空間呢?是的,p_name這個指針變量也會指向一個內存空間
指針在數組中的應用
大家首先得區分一個概念,「數組指針」和「指針數組」的區別。
數組指針
簡單說數組指針就是整個數組都為指針
直接改變數組的某個元素,不會影響到對應元素的變量。
指針數組
簡單說就是數組每個元素都為指針
當然指針數組和數組指針有很多細節需要注意,如果這篇文章閱讀量還可以,咱們后面專門會開一篇講解這個問題。在這里有個簡單的認識即可。希望大家記得多多轉發和點贊哦。
指針在函數中的應用
case1
大家想象一下最終打印出來的a是123 還是456,當然是123.為什么會這樣呢?因為運行到changeData中,把a傳進去之后,相當于執行了一步
所以自然對b進行任何修改都不會影響到a,輸出的自然是123
case2
在這一次函數參數傳遞中,相當于執行了
b就是指向a的指針,所以*b修改了,a自然也會跟著修改。
golang指針和c語言指針的區別
大家知道C語言之所以強大,就是因為c語言支持指針,而且權限特別大,c語言可以對計算機中任何內存的指針進行操作,這樣自然而然也會帶來一些不安全的因素,所以在golang中,「取消了對指針的一些偏移,翻轉等算術運算」(+、-、++、--)所以使用起來更安全。