5.3 指標

Go 具備類似 C/C++ 的指標語法,但是更安全。Go 不允許指標運算,而且它有資源回收器在背後監視著每一個指標;當某一塊記憶體沒有任何指標指向它,Go 才會將那塊記憶體釋放。

Go 不允許指標運算,除非透過 unsafe 套件。參閱官方文件:https://pkg.go.dev/unsafe

宣告一個指標變數的語法是在型別前面加上星號 *

var p *int

這裡 p 是一個指向 int 的指標。由於沒有給初始值,故 p 的內容會是指標的預設值:nil

位址運算子

宣告為指標的變數,其內容就是一個記憶體位址,該位址所在的地方才是變數值所在的記憶體區塊。在操作指標時,除了 *,還會使用 & 符號:

  • 在變數名稱前面加上 & 符號會取得該變數所在的記憶體位址(address)。
  • 在指標變數名稱前面加上 * 符號則代表該指標所指向之變數的內容(value)。

範例:

num := 100   // 編譯器決定 num 是個 int。
ptr := &num  // 編譯器決定 ptr 是個指向變數 num 的指標。
*ptr = 200   // 把 ptr 指向的變數的內容改為 200。

fmt.Println(num)
fmt.Printf("Type of ptr: %T", ptr) // 印出 ptr 的型別名稱。

執行結果:

200
Type of ptr: *int

傳值還是傳址?

Go 只有傳值(pass by value)。也就是說,當我們把一個變數傳入某函式的參數時,該參數會是傳入之變數的新副本;在函式中修改那個參數值並不會改動先前的變數。

如果要讓函式可以修改傳入參數的變數內容,就要使用指標:

func main() {
    num := 100 // 編譯器決定 num 是個 int。

    increase(&num)
    fmt.Println(num) // 印出 101
}

func increase(n *int) {
    *n++
}

從函式回傳指標

Go 函式可以回傳一個指向函式區域變數的指標:

func newInt() *int {
    num := 42
    return &num
}

func main() {
    c := newInt()
    fmt.Println(*c)      // 印出 42
    fmt.Printf("%T", c)  // 印出 *int
}

newInt() 裡面的區域變數 num 所佔據的記憶體不會在函式返回之後立即消失,因為呼叫端 main() 函式有一個指標 c 仍指向 num 所在的記憶區塊。等到 num 所在的記憶區塊完全沒有人參考時,Go 的資源回收器便會將它所佔據的記憶體回收。


先這樣,也許有空時會再更新。   我的其他站點:      

Last modified: 2024-10-15