the basics of using pointer
the variable of pointer type & pointer type
我们需要区分2个概念:
- the variable of pointer type
- pointer type
var pointerToX *int
上面的代码中,*int
是 pointer type,而 pointerToX是 the variable of pointer type 。
我们和常见的变量声明语句,比较一下
var x int
int
是primitive type , 而 x是 the variable of primitive type
总结下:
- pointerToX is the variable of pointer type, *int is pointer type
- x is the variable of value type,int is value type
func main() {
var x int = 10
var pointerToX *int
pointerToX = &x
fmt.Println(*pointerToX)
}
the variable of pointer type & the variable of value type
the variable of pointer type , assign address of memory location to his value
the variable of value type , assign actual value to his value
有的时候,我们也叫做:
- the variable of pointer type
- the variable of value type
package main
import "fmt"
func main() {
var x int32 = 10
var y bool = true
pointerX := &x
pointerY := &y
var pointerZ *string
fmt.Println(pointerX, pointerY, pointerZ)
}
输出
0xc00000a098 0xc00000a09c <nil>
存储方式如下:
![image-20220619091819821](https://wppic-1305237375.cos.ap-nanjing.myqcloud.com/img/image-20220619091819821.png)
&—address operator *—indirection operator
The & is the address operator. It precedes a variable of value type and returns the address of the memory location where the value is stored.
The * is the indirection operator. It precedes a variable of pointer type and returns the variable of pointer type pointed-to value. This is called dereferencing.
var x int32 = 10
pointerX := &x
z := 5 + *pointerX
fmt.Println(z) // 15
从直接寻址 和 间接寻址的角度,来理解*
操作符
寻址,即根据address of memory location,来寻找对应的value
正常情况下,x=5; y= 3+x ,这时,怎么计算y的?
这里,变量x,其实是一串address,当我们开始计算y时,我们根据变量x的address,进行寻址,找到value是5,然后将5 和 3 相加,得到8 。最后,将8存储到y的value中。
也就是说,我们认为的变量相加,其实编译完成后,其实是一串address,比如0xc00000a09c,在计算时,我们根据address,进行寻址,找到对应的value值,完成计算。
那么*
是间接寻址。顾名思义,和上面普通情况下的直接寻址不同,间接寻址,是2个直接寻址步骤的组合。
var x int32 = 10
pointerX := &x
z := 5 + *pointerX
fmt.Println(z) // 15
上面 z计算时,*
是怎么计算的呢?我们首先根据pointerX的address,进行寻址,找到对应的value,这个value其实也是一个address,我们将value中的address记作address2,我们继续根据address2再次寻址,找到对应的value是10,然后,我们让5 和 10 进行相加,就得到了15,将15存储到变量z的value中。
也就是说,*
计算时,我们进行了2次寻址操作,这个就叫做间接寻址。
declare the variable of pointer type & assign
func main() {
var x int = 10
var pointerToX *int
pointerToX = &x
fmt.Println(*pointerToX)
}
pointerToX is the variable of pointer type
通过&
操作符,为pointerToX赋值
modify params reflect origin variable & pointer
当我们将一个变量,作为参数,传入到function中 或者 method中,如果在function中 ,修改了这个参数的值,这个时候,有一个问题,需要我们思考下,即 对参数值的修改,是否会影响 原来变量的值呢?
先说答案:有可能会影响,有可能不影响。
- 如果这个参数,是使用pointer来实现的,那么会影响原来变量的值,比如map 、slice
- 如果这个参数,是使用value来实现的,那么不会影响原来变量的值,比如primitive 、struct、arrays
non-pointer types: primitives, structs, and arrays,
pointer types: maps and slices
The second implication of copying a pointer is that if you want the value assigned to a pointer parameter to still be therewhen you exit the function, you must dereference the pointerand set the value.
If you change the pointer, you havechanged the copy, not the original.
Dereferencing puts the newvalue in the memory location pointed to by both the originaland the copy
package main
import "fmt"
func failedUpdate(px *int) {
x := 10
px = &x
}
func update(px *int) {
*px = 20
}
func main() {
f := 5
failedUpdate(&f)
fmt.Println(f) //5
update(&f)
fmt.Println(f) //20
}
通过上面的代码,发现,传入一个the variable of pointer type,如果直接更改这个变量的值,不会影响原来的值;但是如果通过*
操作符,会影响原来的值
slice data structure
That’s because a slice is implemented as a struct with three fields:
an int field for length, an int field for capacity, and a pointer to a block of memory
几个重要的场景
1.Changing the values in the slice changes the memory that the pointer points to, so the changes are seen in both the copy and the original.
2.Changes to the length and capacity are not reflected back in the original, because they are only in the copy. Changing the capacity means that the the pointer is now pointing to a new, bigger block of memory.
3.If the slice copy is appended to and there is enough capacity to not allocate a new slice, the length changes in the copy and the new values are stored in the block of memory that’s shared by the copy and the original.
However, the length in the original slice remains unchanged.
This means the Go runtime prevents the original slice from seeing those values since they are beyond the length of the original slice.
The result is that a slice that’s passed to a function can have its contents modified, but the slice can’t be resized.
map data structure
within the Go runtime, a map is implemented as apointer to a struct. Passing amap to a function means that you are copying a pointer.
any modifications made to a map that’s passed to a function are reflected in the original
variable that was passed in.