TL;DR:指针接收器需要在设置其值之前取消引用。这适用于结构和非结构类型。对于结构类型,取消引用由选择器表达式自动完成。
在进一步挖掘之后,我认为这种行为是由于指针接收器不是调用该方法的同一个指针。
运行这段代码sn-p可以看出main()函数中的u指针与defaultIP()方法中的指针不同。本质上,我最终只修改了defaultIP() 方法中的u 指针。可执行示例可以在here找到。
func main() {
var u *userIP
u.defaultIP()
fmt.Printf("main(): address of pointer is %v\n", &u)
fmt.Printf("main(): user IP address is %v\n", u)
}
type userIP net.IP
func (u *userIP) defaultIP() {
defaultIP := userIP("127.0.0.1")
u = &defaultIP
fmt.Printf("defaultIP(): address of pointer is %v\n", &u)
fmt.Printf("defaultIP(): user IP address is %s\n", *u)
}
执行此操作的正确方法是 Tom 的回答中指出的,即在 defaultIP() 方法中取消引用 u。
之前让我感到困惑的是,如果我将 IP 包装为结构中的一个字段,为什么这个示例会起作用?运行代码sn -p可以看出,这两个u指针确实不一样,只是修改了ip字段。可执行示例可以在here找到。
func main() {
u := &userInfo{}
u.defaultIP()
fmt.Printf("main(): address of pointer is %v\n", &u)
fmt.Printf("main(): user IP address is %s\n", u.ip)
}
type userInfo struct{
ip net.IP
}
func (u *userInfo) defaultIP() {
u.ip = net.ParseIP("127.0.0.1")
fmt.Printf("defaultIP(): address of pointer is %v\n", &u)
fmt.Printf("defaultIP(): user IP address is %s\n", u.ip)
}
原来这是由selector expression (x.y) 引起的。引用文档,
选择器自动取消引用指向结构的指针。如果 x 是指向结构的指针,则 x.y 是 (x).y 的简写;如果字段 y 也是指向结构的指针,则 x.y.z 是 ((*x).y).z 的简写,依此类推。如果 x 包含 *A 类型的匿名字段,其中 A 也是结构类型,则 x.f 是 (*x.A).f 的快捷方式。
所以在我的例子中,u.ip 表达式在修改 ip 字段之前取消引用 u,该字段基本上转换为(*u).ip。