最近在SO上找到了一个很有意思的问题:SO

这个问题是关于一个指针在外部函数的赋值,当然,解决方法也很简单。

type userIP net.IP

func main() {
  var u *userIP
  u.defaultIP()
  fmt.Printf("%v\n", u) 
}

func (u *userIP) defaultIP() {
  defaultIP := userIP("127.0.0.1")
  u = &defaultIP
}

但是为什么会这样?如果是学过C风格指针的话应该会发现这条语句是很奇怪的,从语法上讲u中存放的地址会被改变,但是实际上它并不会改变(PS:原来的这个代码需要修改一下,不然会有dereference nil的错误)

修改后的例子 Link to heading

package main

import (
	"fmt"
	"net"
)

type userIP net.IP
func main() {
	s:= userIP("123.2.2.1")
	var u *userIP = &s
	fmt.Printf("address of s %p\n",&s)
	fmt.Printf("what's in u? u = %p, &u = %p\n",u,&u)
	fmt.Println("In main function")
	fmt.Printf("main(): address of pointer is %v, address inside pointer is %p\n", &u,u)
	fmt.Printf("main(): user IP address is %s\n", *u)
	u.defaultIP()
	fmt.Println("After executing defaultIP")
	fmt.Printf("main(): address of pointer is %v, address inside pointer is %p\n", &u,u)
	fmt.Printf("main(): user IP address is %s\n", *u)
	hyperIP(&u)
	fmt.Println("After executing hyperIP")
	fmt.Printf("main(): address of pointer is %v, address inside pointer is %p\n", &u,u)
	fmt.Printf("main(): user IP address is %s\n", *u)
}

func (u *userIP) defaultIP() {
	defaultIP := userIP("127.0.0.1")
	u = &defaultIP
	fmt.Println("In function defaultIP")
	fmt.Printf("defaultIP(): address of pointer is %v, address inside pointer is %p\n", &u,u)
	fmt.Printf("defaultIP(): user IP address is %s\n", *u)
}

func hyperIP(u **userIP) {
	defaultIP := userIP("129.0.0.1")
	*u = &defaultIP
	fmt.Println("In function hyperIP")
	fmt.Printf("hyperIP(): address of pointer is %v, address inside pointer is %p\n", &u,u)
	fmt.Printf("hyperIP(): user IP address is %s\n", *u)
}

通过上面这个例子可以进一步揭示问题,输出结果如下:

address of s 0xc0000044c0
what's in u? u = 0xc0000044c0, &u = 0xc000006028
In main function
main(): address of pointer is 0xc000006028, address inside pointer is 0xc0000044c0
main(): user IP address is 123.2.2.1
In function defaultIP
defaultIP(): address of pointer is 0xc000006038, address inside pointer is 0xc000004520
defaultIP(): user IP address is 127.0.0.1
After executing defaultIP
main(): address of pointer is 0xc000006028, address inside pointer is 0xc0000044c0
main(): user IP address is 123.2.2.1
In function hyperIP
hyperIP(): address of pointer is 0xc000006040, address inside pointer is 0xc000006028
hyperIP(): user IP address is &129.0.0.1
After executing hyperIP
main(): address of pointer is 0xc000006028, address inside pointer is 0xc000004580
main(): user IP address is 129.0.0.1

可以看到,对于主函数中的指针u,其地址为0xc000006028,其存放的地址为0xc0000044c0,这个与声明的变量是一致的。 问题在于,传入函数中的指针的地址是变动的,也就是传入函数的指针并不是原来的指针(这很正常,因为golang并没有引用传值,每一个变量的地址都是不一样的)。

所以,单纯修改指针中存放的内容是没有任何用处的。如果假设指针是杯子,里面存放的内容是某种液体,现在main函数中的u杯子里面装的是水,那么defaultIP杯子中装的就是酱油。如果想要让main的u杯中也装入酱油,唯一的方法就是把酱油倒进u杯中,因为go不支持对两个杯子的替换。