指针
学Java以来,忽略了指针和内存地址这些概念,Java帮我们封装了对象,简化了对象引用之间的关系。在Go语言中,又帮我们回忆起这些概念。
内存地址
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。
所以一个常量或者是没有赋值的量是没有内存地址的
i := 1997
fmt.Printf("num is : %d, it's location in memory: %p\n",i,&i)
//输出:num is : 1997, it's location in memory: 0x1400011a168
Go语言取地址的符号是&,从地址取值用*
易得 var == *(&var)
0x开头代表十六进制。32位的CPU理论最多支持4GB的内存空间,CPU只能寻址2的32次方(4GB)。64位操作系统的寻址能力就是2的64次方。也就是17179869184G。当然这是理论还得看具体主板支持。
Go的指针
两个核心概念:
- 类型指针,允许对这个指针类型的数据进行修改,传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。
- 切片,由指向起始元素的原始指针、元素数量和容量组成
类型指针
i := 1997
address := &i
fmt.Printf("num is : %d, it's location in memory: %p ,type is: %T \n",i, address,reflect.TypeOf(address))
//num is : 1997, it's location in memory: 0x1400011a168 ,type is: *int
i代表变量,&i代表变量i的地址,address接受其地址对应类型是*T,这里是*int
Java中的参数传递,传递的是值的拷贝(只是这个有时候是指针),但是在Go中你可以使用指针来传递这个值,它直接指向了这个值的内存地址,并且只占用了4个或者8个字节。
Go 默认使用按值传递来传递参数,也就是传递参数的副本。函数接收参数副本之后,在使用变量的过程中可能对副本的值进行更改,但不会影响到原来的变量 。如果你希望函数可以直接修改参数的值,而不是对参数的副本进行操作,你需要将参数的地址(变量名前面添加&符号,比如 &variable)传递给函数,这就是按引用传递 。此时传递给函数的是一个指针 。方法中常写*sync.Mutex 来接受参数
变量、指针和地址三者的关系是:每个变量都拥有地址,指针的值就是地址,变量加&等于指针,指针加*等于指向变量。
所以指针也可以用来互换值。Go语言的flag包中,定义的指令以指针类型返回。(用于命令行解释)
//定义一个类型,用于增加该类型方法
type sliceValue []string
//new一个存放命令行参数值的slice
func newSliceValue