[Golang] 指標 Pointers
Pointers @ A Tour of Go
TL;DR
- 會需要「mutate」原本資料的 methods 就需要傳入的是 pointer
- 單純是「顯示」原本資料用的 methods 就不需要傳入 pointer
// *T 是一種型別,指的是能夠指向該 T 的值的指標,它 的 zero value 是 nil
// *T means pointer to value of type T
var p *int // nil
// &variable 會產生該 variable 的 pointer
i := 42
p := &i // & 稱作 address of pointer
fmt.Println(p) // 0xc0000b4008
fmt.Println(*p) // 透過 pointer 來讀取到 i
// 當 function receiver 這裡使用了 *type 時
// 這裡拿到的 p 會變成 pointer,指的是存放 p 的記憶體位址
func (p *person) updateNameFromPointer(newFirstName string) {
// *variable 表示把該指摽對應的值取出
p.firstName = newFirstName // 等同於 (*p).firstName = newFirstName
}
// 當沒有使用 *type 時
// 每次傳進來的 p 都會是複製一份新的(by value)
func (p person) updateName(newFirstName string) {
p.firstName = newFirstName
}
func main() {
jim := {
firstName: "Jim"
}
jim.updateNameFromPointer("Aaron") // It works as expected
jim.updateName("Aaron") // It doesn't work as expected
}
為什麼需要使用指標(Pointer)
信息
Go (Golang) Tutorial #14 - Pointers @ The Net Ninja
指標(Pointer)是用來存放記憶體位置(Memory Address)。
Go 是一個 pass by value 的程式語言,也就是每當我們把值放入函式中時,Go 會把這個值完整的複製一份,並放到新的記憶體位址,以下面的程式碼為例:
package main
import "fmt"
// 建立 person type
type person struct {
firstName string
lastName string
}
// 建立 person 的 function receiver
func (p person) updateName(newFirstName string) {
fmt.Printf("Before update: %+v\n", p)G
p.firstName = newFirstName
fmt.Printf("After update: %+v\n", p)
}
func (p person) print() {
fmt.Printf("Current person is: %+v\n", p)
}
func main() {
jim := person{
firstName: "Jim",
lastName: "Party",
}
// Before update: {firstName:Jim lastName:Party}
jim.updateName("Aaron")
// After update: {firstName:Aaron lastName:Party}
jim.print() // Current person is: {firstName:Jim lastName:Party}
}
會發現到雖然呼叫了 jim.updateName()
這個方法,但 jim 的 firstName 並沒有改變。這是因為當我們呼叫 jim.updateName()
時,Go 會把呼叫此方法的 jim 複製一份到新的記憶體位置,修改的 jim 其實是存在另一個記憶體位置,這就是為什麼當我們在 updateName()
這個函式中呼叫 p
時,會看到 firstName 是有改變的,但最後呼叫 jim.print()
時,卻還是得到舊的 jim。