前言
指標大概是我一開始學習golang最不適應的概念,最一開始學程式是由JavaScript入門,到wehelp後再學習用python 的flask框架寫網頁,這兩種語言都沒有指標的概念。而Go為了實現更高效的演算法及展現其高併發的特性,所以存有指標的方法來操作內存,當然相信自己學習時間不算久,也非EE 或CS背景,對指標瞭解可能還不夠全面,只能盡力就我了解的進行說明,如果有錯還請各方大神指正。
值 & 指標
當我們將int、string、struct這類的值傳給函式的時候(圖一),Go語言會在函式中複製這些值,建立新的變數,也就代表如果是在函式對參數做修改時候,原始的值是不會有影響的,而如果要修改原本的值,就要透過所謂的 指標變數。
(圖一,圖片來源 : Udemy Go: The Complete Developer’s Guide (Golang))
我們可以在記憶體儲存資料非常簡單看成是一個抽屜,每個變數到會找到一個抽屜來儲存資料,而每個抽屜都有一個地址對應一筆資料(圖二),所謂的值與指標變數的關係可以參考圖三,也可以幫助理解。
- 宣告一個int型別的變數x,其值初始化為3,這個3在記憶體裡面會有個地址0x88FFF。並可以透過在變數前面加上ampersand符號,取得該變數在記憶體的地址。
- 宣告一個int型別的指標變數xPtr,*int代表一個指向int的指針,為一種type description。並透過將xPtr初始化為&x,取得該變數在記憶體的地址。
- 最後如果有需要存取原本的值,或修改原本的值,可以透過在指標變數前面加上
*
符號進行反解(dereferencing)。如果(ex :fmt.Println(*xPtr)
可以得到3 )。
(圖二,自行繪製) (圖三,圖片來源 : Golang 指標基礎 Pointer - 記憶體位址、指標變數與資料型態、反解指標 By 彭彭)
介紹完值和指標宣告與反解的流程,會發現用到兩次*
符號,但這兩次其實是代表不同個功用,參考下圖四
(圖四,自行繪製)
同時繪製圖五再次說明*
符號與&
符號的當作運算符號時候的功能
(圖五,自行繪製)
實作程式碼
以下面程式碼為例,一開始會先印出x等於3,但當我們將int傳給函式的時候,會在函式複製值,建立新的變數,所以如果要修改原本的值,傳入的變數必須為指標變數,故modifyInt函式的參數為(x *int)
。
而當我們定義型別為*int
,傳入的參數就必須是記憶體位置,故使用&x
作為參數帶入modifyInt()函式,最後透過在modifyInt()使用*x
進行反解,取得原本記憶體位置的值並重新賦值為50,可以發現不管是一開始的x變數,或是執行完modifyInt()函式的x變數,其值都變成50了。
package main
import "fmt"
var x int=3
func modifyInt(x *int) {
*x = 50
fmt.Println("Inside function :", *x)
}
func main() {
fmt.Println("At first, x eqaul to :", x)
modifyInt(&x)
fmt.Println("Outside function :", x)
}
// At first, x eqaul to : 3
// Inside function : 50
// Outside function : 50