前言
如同其他的編譯語言 (compiled language),Go 支援指標 (pointer)。在 C/C++ 中,指標是必經的門檻;但指標對初學者來說不是很好懂,時常會因誤用指標而造成 segment fault 等錯誤,許多程式學習者對指標有不好的回憶。不過,在 Go 裡面,指標比較簡化,不僅沒有指標運算,也不需要手動控制記憶體釋放。
建立指標
指標本身存的值是指向另一個值的記憶體位置 (memory address),我們通常不會直接使用指標的值,而會透過指標間接操作另一個值。在以下實例中,我們建立一個指向整數的指標:
package main
import (
"fmt"
"log"
)
func main() {
n := 2
// Reference the adress from the variable.
nPtr := &n
// Print out the address.
fmt.Println(nPtr)
// Dereference the pointer to get the value.
if !(*nPtr == 2) {
log.Fatal("Wrong value")
}
}
動態配置記憶體
我們也可以動態配置記憶體,見下例:
package main
import (
"fmt"
"log"
)
func main() {
// Allocate a chunk of memory.
nPtr := new(int)
// Assign the value indirectly.
*nPtr = 2
// Print out the address.
fmt.Println(nPtr)
// Dereference the pointer to get the value.
if !(*nPtr == 2) {
log.Fatal("Wrong value")
}
}
實際上,我們比較少對基礎型別進行動態記憶體分配,但我們可以對結構等複合型別動態配置記憶體,如下例:
package main
import (
"fmt"
)
type Point struct {
x float64
y float64
}
func main() {
p := new(Point)
p.x = 3.0
p.y = 4.0
fmt.Println(fmt.Sprintf("(%.2f, %.2f)", p.x, p.y))
}
對結構動態分配記憶體相當有用,Go 物件導向程式大量使用這種語法。
我們前述的 make 函式其實也是動態分配記憶體的一種語法,但 make 回傳的不是指標,而是該型別本身;因此,我們不需要使用指標的語法操作陣列、切片和 map,這是 Go 簡化語法的一種方式。
結語
在 Go 裡面,指標除了用來和 C 函式庫互動外,當變數較大時,傳遞指標較傳遞整個變數有效率得多,日後談到函式和物件時都會用到指標。由於 Go 不需手動管理記憶體,也沒有指標運算,Go 指標較 C 指標簡化許多。