最近在教學 Golang 的記憶體處理細節時,重新對 Pointer
和 Pointer Receiver
做了梳理。這兩者經常一起出現,但實際上代表不同層面的設計。
Pointer:一種資料型別
在 Go 裡,指標(Pointer)本質上就是「儲存某個變數記憶體位置的變數」。
var a int = 10幾個重點:
var p *int = &a
p
的型別是*int
,表示它指向一個int
的位址&a
是取變數a
的位址*p
是從記憶體中取出p
指向的實際值
這種語法對 C/C++ 開發者來說應該不陌生。Go 的指標語法相對簡潔,不支援指標運算,也不能對記憶體地址做太細的操作。
Pointer Receiver:方法定義時的接收者類型
Go 的 method
語法允許你定義某個類型的方法,在定義時,receiver
可以是值,也可以是指標。
type Counter struct {
value int
}
func (c *Counter) Increment() {
c.value++
}
這裡的 (c *Counter)
表示這是一個「指標接收器」,重點有幾個:
- 如果用值接收器(
c Counter
),那就是複製一份;方法裡的修改不會影響外部 - 用指標接收器(
*Counter
)的話,修改會作用在原本那個實例上
Go 語言會自動幫你解參考,呼叫方法時不需要寫 (*c).Increment()
,直接 c.Increment()
就行,即使 c
是實例不是指標也會自動轉換
自動幫你解參考 => 最最重要的golang特性
使用情境的判斷
如果一個方法會修改 receiver 的內容,應該使用指標接收器。如果不會修改,兩者皆可,但實務上為了一致性,通常會全部都使用 *T
。
這一點在標準庫中也能觀察到,例如 bytes.Buffer
的大多數方法就是用 pointer receiver,因為每次操作都會改變狀態。
這不是一個難理解的主題,但常常混淆,也容易在 struct method 設計時留下不一致的選擇。釐清概念後,實務上的判斷與維護也會更直覺。